3

从上一个问题:

做一个静态断言模板类型是另一个模板

Andy Prowl 为我提供了这段代码,它允许我将static_assert模板类型视为另一种模板类型:

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 在他的回答中所写,无法实现对您发布的解决方案的同样通用的扩展。

但是,如果您可以放弃一些通用性,您可以编写一个特定于的类型特征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 所指出的,它不起作用的一个地方是,如果您有一个派生自多个实例化的类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那么模式匹配可能会在哪里。 ...可能需要更换。我想不出一种方法来处理通过测试的多个基地......

我认为我们可以做得更好。调用上述方法有三种可能的结果。

首先,一个父母或自己匹配测试。其次,它与包罗万象相匹配。第三,它是模棱两可的,因为它可以以不止一种方式通过测试。

如果我们改进 catch-all 以捕获低优先级(Ts...&&可能)的所有内容,我们可以将失败编译为成功条件。

SFINAE从,从 match-one返回 true ,true从 catch-all match-none 返回 false。

于 2013-07-01T02:55:35.363 回答
1

你不能在 C++11 中做到这一点。您基本上必须量化所有类类型并检查它们中的任何一个是否是候选人的基础。

TR2 中有一个提案(我听说现在已经不复存在),可能将其纳入 C++14,添加特征std::basesstd::direct_bases枚举给定类的基类,从而有效地解决您的问题(即将您现有的特征应用于每个基类)。

<tr2/type_traits>如果有帮助的话,GCC 确实提供了这个特性。

于 2013-06-30T23:22:52.803 回答