13

以前の質問から:

テンプレート型が別のテンプレートであることを 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; //success
  return 0;
}

これはうまくいきます。

しかし、このようなコードを のエイリアスを使用するように変更するとfoo、事態は悪化します。

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 {};

//Added: alias for foo
template<typename T>
using foo_alt = foo<T>;

template<typename FooType>
struct bar {
  //Changed: want to use foo_alt instead of foo here
  static_assert(is_instantiation_of<foo_alt,FooType>::value, ""); //fail
};

int main(int,char**) {
  //both of these fail:
  bar<foo<int>> b;
  bar<foo_alt<int>> b2;

  return 0;
}

これは解決できますか?

4

2 に答える 2

11

いいえ、解決できません (少なくとも設計を大幅に変更しない限り)。問題は、C++11 標準のパラグラフ 14.5.7/2 で述べられているように、テンプレート エイリアス名が推定されないことです。

template-id がエイリアス テンプレートの特殊化を参照する場合、エイリアス テンプレートの type-id の template-parameters を template-arguments に置き換えることによって取得される関連する型と同等です。[注: エイリアス テンプレート名は決して推測されません。—注記終了]

この段落では、次の例も示しています。

template<class T> struct Alloc { / ... / };
template<class T> using Vec = vector<T, Alloc<T>>;
Vec<int> v; // same as vector<int, Alloc<int>> v;

...

template<template<class> class TT>
void f(TT<int>);
f(v); // error: Vec not deduced                          <=== Relevant

...

—<em>例の終了]

foo_altあなたの具体的なケースでは、問題は、部分的な特殊化を一致させようとすると、コンパイラはあなたの型が(エイリアス テンプレートの名前であるため)のインスタンス化であると推測せずfoo_alt、プライマリ テンプレートが選択されることです。

エイリアス テンプレートを使用する場合は、一般性を少し放棄して、 に固有の型特性を作成する必要がありますfoo

#include <type_traits>

template<typename T>
struct foo {};

template<typename T>
struct is_instantiation_of_foo : std::false_type { };

template<typename...Ts>
struct is_instantiation_of_foo<foo<Ts...>> : std::true_type { };

次に、次のように使用できます。

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

これで、次のプログラムのどのアサーションも起動しなくなります。

template<typename T>
using foo_alt = foo<T>;

int main(int,char**) {
  // None of these fail:
  bar<foo<int>> b;
  bar<foo_alt<int>> b2;

  return 0;
}

これが実際のです。

于 2013-06-30T18:00:16.127 に答える