37

C ++ 11の新機能を利用するために、いくつかのC++コードのアップグレードに取り組んでいます。私は、常にではありませんが、ほとんどの場合、定数式を返す基本型を返すいくつかの関数を持つトレイトクラスを持っています。機能の有無によって違うことをしたいですconstexpr。私は次のアプローチを思いついた:

template<typename Trait>
struct test
{
    template<int Value = Trait::f()>
    static std::true_type do_call(int){ return std::true_type(); }

    static std::false_type do_call(...){ return std::false_type(); }

    static bool call(){ return do_call(0); }
};

struct trait
{
    static int f(){ return 15; }
};

struct ctrait
{
    static constexpr int f(){ return 20; }
};

int main()
{
   std::cout << "regular: " << test<trait>::call() << std::endl;
   std::cout << "constexpr: " << test<ctrait>::call() << std::endl;
}

追加のint/パラメーターは、 SFINAE...の後に両方の関数が使用可能である場合に、解像度をオーバーロードすることによって最初の関数が選択されるようにするためにあります。

これをClang3.2でコンパイルして実行すると、次のようになります。

regular: 0
constexpr: 1

したがって、これは機能しているように見えますが、コードが合法的なC++11であるかどうかを知りたいと思います。特に、 SFINAEのルールが変更されたことが私の理解です。

4

2 に答える 2

14

注: OP コードが実際に有効かどうかについて、ここで質問を開きました。以下の書き直した例は、どのような場合でも機能します。


しかし、コードが合法的なC++ 11であるかどうかを知りたい

デフォルトのテンプレート引数は少し変わっていると思われるかもしれませんが、そうです。個人的には、次のスタイルの方が好きです。これは、型以外のテンプレート パラメーターを使用してdecltype:

#include <type_traits>

namespace detail{
template<int> struct sfinae_true : std::true_type{};
template<class T>
sfinae_true<(T::f(), 0)> check(int);
template<class>
std::false_type check(...);
} // detail::

template<class T>
struct has_constexpr_f : decltype(detail::check<T>(0)){};

実例。


説明時間〜

デフォルトのテンプレート引数のインスタンス化のポイントは、その関数テンプレートのインスタンス化のポイント、つまり、あなたの場合は inであるため、元のコードは機能します†</sup> main

§14.6.4.1 [temp.point] p2

関数テンプレート [...] が、その関数テンプレート [...] のデフォルト引数の定義を使用する方法で呼び出された場合、デフォルト引数のインスタンス化のポイントは、関数テンプレート [...] のインスタンス化のポイントです。 ...]。

あとはいつものSFINAEルールです。


† 少なくとも私はそう思いますが、標準では完全に明確ではありません。

于 2013-03-06T00:11:41.543 に答える