检查嵌套的模板类

时间:2014-06-09 01:42:08

标签: c++ templates c++11 typetraits

我正在尝试构建一个特征,用于检查是否存在嵌套的模板化类。我需要检查一个类O是否有一个带有模板参数inner的嵌套类T

template <typename O, typename T> struct has_inner {
    static const bool value = std::is_class<typename O::template inner<T> >::value;
};

但是,这不能正常工作。给出了两个示例类dummyok

struct dummy {};
struct ok {
    template <typename T>
    struct inner {
    };
};

检查ok

std::cout << std::boolalpha << has_inner<ok, float>::value << std::endl;

会有效,而对dummy

进行检查
std::cout << std::boolalpha << has_inner<dummy, int>::value << std::endl;

将无法使用错误

在clang 3.2上编译
error: 'inner' following the 'template' keyword does not refer to a template
    static const bool value = std::is_class<typename O::template inner<T> >::value;
                                                                 ^~~~~
note: in instantiation of template class 'has_inner<dummy, int>' requested here
    std::cout << std::boolalpha << has_inner<dummy, int>::value << std::endl;

似乎编译器在将模板化表达式传递给std::is_class之前尝试实际形成该模板化表达式。因此,我看到两个解决方案:

  1. 告诉编译器延迟模板扩展,或
  2. 完全采用不同的方法。
  3. 但是,我不知道如何表演,有人可以帮忙吗?

2 个答案:

答案 0 :(得分:3)

问题

您通常使用SFINAE来实现这样的特征,这些特征是您的实施无法利用的。

如上所述,编译器将尝试实例化typename O::template inner<T>,无论它是否可能;如果不可能,编译器将在您的脸上抛出错误诊断。

您需要做的是进行条件检查,以查看T内部是否实际上有模板类,如果它没有实例化,则无需实例化。


解决方案 - SFINAE去救援!

实现可能如下面的代码段所示,接下来会有解释。

namespace impl {
  template<class T, class... Args>
  struct has_inner {
    template<class U, typename = typename U::template inner<Args...>> // (A)
    static std::true_type  test (int);

    template<class U>
    static std::false_type test (...);                                // (B)

    using result_type = decltype (test<T> (0));                       // (C)
  };
}

template<class... Ts>
using has_inner = typename impl::has_inner<Ts...>::result_type;
  

注意:使用decltype(test<T>(0)),我们将拥有 std :: true_type std :: false_type 这是处理 type-traits 结果时的标准行为。


SFINAE 的规则规定,如果函数模板在实例化时会产生无效的函数声明,就好像这个函数不存在一样,编译器会尝试搜索另一个匹配而不是放弃。

这是在(C)发生的事情,我们尝试调用(A)但如果失败(即无效表达式在template<class U, typename ...>内产生,我们将最终调用(B)。

(B)与(A)的成功实例化不是很好的匹配,但如果(A)不能被实例化,(B)就会这样做。

答案 1 :(得分:2)

您需要使用特质类和SFINAE,如下所示:

template<class A, typename B>
struct has_inner
{
private:
    template<class T, typename U>
    static std::true_type has(typename T::template inner<U>*);

    template<class, typename>
    static std::false_type has(...);
public:
    static constexpr auto value = decltype(has<A, B>(nullptr))::value;
};

现在您可以使用它并获得正确的结果:

static_assert(has_inner<ok, float>::value, "ok does not have inner");    // OK
static_assert(has_inner<dummy, float>::value, "dummy does not have inner"); // ERROR