関数の戻り値が constexpr かどうかを判定する

そんな感じの constexpr 関数を書いてみました。
まさに誰得。

[ソース]

#include <type_traits>

template<typename T>
constexpr bool
true_(T){
    return true;
}

template<typename T, typename ...Args, bool = true_(T{}(Args{}...))>
constexpr bool
is_constexpr_impl(bool&&){
    return true;
}

template<typename T, typename ...Args>
constexpr bool
is_constexpr_impl(bool const&&){
    return false;
}

template<typename T, typename ...Args>
constexpr bool
is_constexpr(Args&&...){
    return is_constexpr_impl<T, typename std::decay<Args>::type...>(0);
}


template<
    typename FuncType,
    typename std::add_pointer<FuncType>::type Func,
    typename ...Args,
    bool = true_(Func(Args{}...))
>
constexpr bool
is_constexpr_impl(bool&&){
    return true;
}

template<
    typename FuncType,
    typename std::add_pointer<FuncType>::type Func,
    typename ...Args
>
constexpr bool
is_constexpr_impl(bool const&&){
    return false;
}


template<
    typename FuncType,
    typename std::add_pointer<FuncType>::type Func,
    typename ...Args
>
constexpr bool
is_constexpr(Args...){
    return is_constexpr_impl<FuncType, Func, Args...>(0);
}


struct X{
    constexpr int
    operator ()() const{
        return 0;
    }

    bool
    operator ()(int) const{
        return 0;
    }

    constexpr float
    operator ()(float, float) const{
        return 0;
    }
};

constexpr int
plus(int a, int b){
    return a + b;
}

float
minus(float a, float b){
    return a - b;
}

#include <cmath>


int
main(){
    // 関数オブジェクトの場合は、型をテンプレート引数に、引数型を関数引数に渡して評価
    static_assert( is_constexpr<X>(), "");
    static_assert(!is_constexpr<X>(0), "");
    static_assert( is_constexpr<X>(0.0f, 0.0f), "");

    // 関数の場合は、第一引数に関数型、第二引数に関数ポインタを渡す
    static_assert( is_constexpr<decltype(plus), &plus>(0, 0), "");
    static_assert(!is_constexpr<decltype(minus), &minus>(0.0f, 0.0f), "");

    
    // コンパイラ依存になりそうな関数とか
    static_assert(is_constexpr<decltype(sin), &sin>(0.0), "");
    static_assert(is_constexpr<decltype(cos), &cos>(0.0), "");
    static_assert(is_constexpr<decltype(tan), &tan>(0.0), "");

    return 0;
}

デフォルトテンプレート引数で関数を評価して、それで SFINAE しています。
とりあえず、gcc 4.7 では動いていますね。
コンパイラに依存しそうな constexpr 関数(math とか get とか forward とか)を切り替える場合に使える…かな?
あと引数型にデフォルトコンストラクタがない場合は動きません。
にょろーん

[コンパイラ]

  • g++ (GCC) 4.7.0 20111210 (experimental)