LoginSignup
9
7

More than 5 years have passed since last update.

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

Posted at

ブログ記事からの転載です。

そんな感じの 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)
9
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
7