3

以前の質問から:

テンプレート型が別のテンプレートであることを static_assert する

static_assertAndy Prowl は、テンプレート タイプが別のテンプレート タイプであることを確認できる次のコードを提供してくれました。

template<template<typename...> class TT, typename... Ts>
struct is_instantiation_of : public std::false_type { };

template<template<typename...> class TT, typename... Ts>
struct is_instantiation_of<TT, TT<Ts...>> : public std::true_type { };

template<typename T>
struct foo {};

template<typename FooType>
struct bar {
  static_assert(is_instantiation_of<foo,FooType>::value, ""); //success
};

int main(int,char**)
{
  bar<foo<int>> b;
  return 0;
}

これはうまくいきます。

しかし、これは のサブクラスでは機能しませんfoo<whatever>:

template<template<typename...> class TT, typename... Ts>
struct is_instantiation_of : public std::false_type { };

template<template<typename...> class TT, typename... Ts>
struct is_instantiation_of<TT, TT<Ts...>> : public std::true_type { };

template<typename T>
struct foo {};

template<typename FooType>
struct bar {
  static_assert(is_instantiation_of<foo,FooType>::value, ""); //fail
};

//Added: Subclass of foo<int>
struct foo_sub : foo<int> {
};

int main(int,char**)
{
  bar<foo_sub> b; //Changed: Using the subclass
  return 0;
}

Andy Prowl のis_instantiation_ofコードを拡張して、サブクラスを許可することはできますか?

4

4 に答える 4

2

KerrekSB が彼の回答に書いたように、投稿したソリューションを同様に一般的に拡張することはできません。

ただし、ジェネリック性を少し放棄しても問題ない場合は、(派生から基底への変換が型推定中に実行される数少ない変換の 1 つであるという事実を利用して) に固有の型特性を記述できますfoo

#include <type_traits>

template<typename T>
struct foo {};

template<typename T>
constexpr std::true_type test(foo<T> const&);

constexpr std::false_type test(...);

template<typename T>
struct is_instantiation_of_foo : public decltype(test(std::declval<T>())) { };

次に、次のように使用します。

template<typename FooType>
struct bar {
  static_assert(is_instantiation_of_foo<FooType>::value, "");
};

struct foo_sub : foo<int> {
};

int main(int,char**)
{
  bar<foo_sub> b; // Will not fire
  return 0;
}

これが実際のです。

于 2013-06-30T23:34:38.993 に答える
2

これは多くの場合に機能するようです:

#include <iostream>
#include <utility>

template <typename T> struct foo { };

struct foo_sub : foo<int> { };

// A fallback function that will only be used if there is no other choice
template< template <typename> class X >
std::false_type isX(...)
{
  return std::false_type();
}

// Our function which recognizes any type that is an instantiation of X or 
// something derived from it.
template< template <typename> class X, typename T >
std::true_type isX(const X<T> &)
{
  return std::true_type();
}

// Now we can make a template whose value member's type is based
// the return type of isX(t), where t is an instance of type T.
// Use std::declval to get a dummy instance of T.
template <template <typename> class X,typename T>
struct is_instantiation_of {
  static decltype(isX<X>(std::declval<T>())) value;
};

template <typename FooType>
struct bar {
  static_assert(is_instantiation_of<foo,FooType>::value,"");
};

int main(int,char**)
{
  //bar<int> a;  // fails the static_assert
  bar<foo<int>> b;  // works
  bar<foo_sub> c;  // works
  return 0;
}

Yakk が指摘したように、それが機能しない場所の 1 つは、の複数のインスタンス化から派生したクラスがある場合ですfoo

struct foo_sub2 : foo<int>, foo<double> { };
于 2013-07-01T03:38:16.323 に答える
1

携帯電話なので、うまくいかないかもしれません。

目標はSFINAE、オーバーロードを使用して、「このコンパイル時の特性の質問に一致する基本クラスはありますか?」という質問をすることです。

template<template<typename>class Test>
struct helper {
   static std::false_type test(...);
   template<typename T, typename=typename std::enable_if< Test<T>::value >
   static std::true_type test(T const&);
};
template<template<typename>class Test, typename T, typename=void>
struct exactly_one_base_matches :std::false_type {};
template<template<typename>class Test, typename T>
struct exactly_one_base_matches<Test,T,
  typename std::enable_if<decltype(helper<Test>::test(std::declval<T>()))::value>::type>
:std::true_type {};

それが一般的なテストで機能しない場合は、testパターン マッチングを実行するテストが機能する可能性があります。 ...交換が必要な場合があります。テストに合格した複数の拠点を処理する方法が思い浮かびません...

私たちはもっとうまくやれると思います。上記を呼び出した場合、3 つの結果が考えられます。

まず、1 つの親または自己がテストに一致します。第二に、キャッチオールに一致します。第三に、複数の方法でテストに合格する可能性があるため、あいまいです。

キャッチオールを改善して、すべてを低い優先度でキャッチするようにすると (Ts...&&おそらく)、コンパイルに失敗して成功条件にすることができます。

SFINAE、 match-one からtrue を返しtrue、catch-all match-none から false を返します。

于 2013-07-01T02:55:35.363 に答える
1

C++11 ではできません。基本的に、すべてのクラス タイプを定量化し、それらのいずれかが候補のベースであるかどうかを確認する必要があります。

TR2 (現在は廃止されたと聞いています) には、特性を追加std::basesstd::direct_bases、特定のクラスの基本クラスを列挙することで問題を効果的に解決する (つまり、既存の特性を各基本クラス)。

GCC は<tr2/type_traits>、役立つ場合、この特性を で提供します。

于 2013-06-30T23:22:52.803 に答える