3

ValueType定義したクラス (typedef) から typedef が指す型を取得しようとしています。ただし、これが失敗した場合は、指定された型を返すようにします (たとえば、 a を指定した場合は、 adoubleを返しますdouble)。これは私がこれまでに持っているものです:

struct myClass { typedef double ValueType; };

template < typename V, typename U = typename V::ValueType>
struct base_type { typedef U type; };
template < typename V >
struct base_type< V, V > { typedef V type; };

static_assert( std::is_same < typename base_type< myClass >::type , double >::value, 
    "base_type doesn't work" ); //This works.
static_assert( std::is_same < typename base_type< double >::type , double >::value,
    "base_type doesn't work" ); //This returns "error: 'double' is not a class, struct, or union type"

ただし、これは機能しません。2 番目の static_assert は失敗します。明らかに、2 番目の定義が呼び出されることはありませんが、その理由はわかりません (最初の定義より確実に一致します)。

何か案は?

4

5 に答える 5

5

あるいは

template < typename V, typename = void>
struct base_type { typedef V type; };
template < typename V >
struct base_type< V, 
                 typename base_type<void, typename V::ValueType>::type > { 
    typedef typename V::ValueType type; 
};

私たちは皆、これらの粗雑で醜い SFINAE ハックをどのように愛しています :)

于 2013-03-13T18:30:39.947 に答える
5

効果的な SFINAE には関数を使用する必要があります。

新しい C++11 機能を使用すると、次のようになります。

template <typename T> auto get_base_type(int) -> typename T::ValueType;
template <typename T> auto get_base_type(...) -> T;

template <typename T>
struct base_type { using type = decltype(get_base_type<T>(0)); };
于 2013-03-13T18:27:17.020 に答える
2

ウィキペディアから 以下は私にとってはうまくいきます。あなたが望むことをすると思います。

#include <type_traits>

template <typename T>
struct has_typedef_ValueType {
// Types "yes" and "no" are guaranteed to have different sizes,
// specifically sizeof(yes) == 1 and sizeof(no) == 2.
typedef char yes[1];
typedef char no[2];

template <typename C>
static yes& test(typename C::ValueType*);

template <typename>
static no& test(...);

// If the "sizeof" the result of calling test<T>(0) would be equal to the sizeof(yes),
// the first overload worked and T has a nested type named foobar.
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};

struct myClass { typedef double ValueType; };

template < class V, bool b = has_typedef_ValueType<V>::value >
struct base_type { typedef typename V::ValueType type; };
template < typename V>
struct base_type <V, false> { typedef V type; };

static_assert( std::is_same < typename base_type< myClass >::type , double >::value,     "base_type doesn't work" ); //This works.
static_assert( std::is_same < typename base_type< double >::type , double >::value, "base_type doesn't work" ); //This returns "error: 'double' is not a class, struct, or     union type"

int main() {}
于 2013-03-13T18:24:23.143 に答える
2
#include <type_traits>
#include <utility>

template < typename V, typename=void>
struct base_type { typedef V type; };
template < typename V >
struct base_type<
  V,
  typename std::enable_if<
    std::is_same<
      typename V::ValueType,
      typename V::ValueType
    >::value
  >::type
>
{
  typedef typename V::ValueType type;
};

これはかなり一般的なテクニックです。基本ケースには、デフォルトでvoid.

特殊化はそのtypename std::enable_if< expression >::type代わりに a をvoid行い、式が有効かつ真であることが有効な特殊化 IFF です。

この場合、単純なstd::is_same< V::value_type, V::value_type >::value. 私自身のコードでvalid_type< typename V::value_type >::valueは、単純に次のように書くことが知られています。

template<typename>
struct valid_type:std::true_type {};

常に真の特性クラス。

さて、このvoidトリックにはいくつかの問題があります。しかし、私はそれがうまく一般的だと思います。

于 2013-03-13T18:28:40.140 に答える
1

doublebase_type特殊化は 2 つの型が渡され、両方が同一である場合にのみ呼び出されるため、特殊化はインスタンス化されません。2 番目のタイプはオプションですが、指定されていない場合はデフォルトで埋められ、typename V::ValueTypeこれはもちろん失敗しdouble::ValueTypeます。

完全を期すために、base_type<V, V>専門化は次のタイプに対してインスタンス化されます。

struct foo { typedef foo ValueType; };

static_assert(std::is_same<base_type<foo>::type, foo>::value, "Failed");
于 2013-03-13T18:29:52.067 に答える