2012-12-04 37 views
2

我有以下结构代码:麻烦与元函数,用于识别类内模板类

template <typename T> 
struct Foo 
{ 
    struct Bar 
    { 
    int data; 
    }; 
}; 

我想写元函数它会告诉我,如果一个类型是富或酒吧。第一个是简单的:

​​

然而,同样的方法不适用于酒吧工作:

template <typename T> 
struct is_bar : boost::mpl::false_ 
{}; 

template <typename T> 
struct is_bar<typename Foo<T>::Bar> : boost::mpl::true_ 
{}; 

此代码是由编译器拒绝。 GCC说:

main.cpp:38:8: error: template parameters not used in partial specialization: 
main.cpp:38:8: error:   ‘T’ 

奇怪的是,铛将编译的代码,但它发出警告,元函数不起作用(始终为false):

main.cpp:38:8: warning: class template partial specialization contains a template parameter that can not be deduced; 
     this partial specialization will never be used 
struct is_bar<typename Foo<T>::Bar> : boost::mpl::true_ 
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
main.cpp:37:20: note: non-deducible template parameter 'T' 
template <typename T> 
       ^

是否有针对此问题的解决方法吗?一个C++ 11特定的解决方案将会很好。

+5

正如Clang所说,“typename Foo :: Bar'是一个不可推卸的上下文。这与要求编译器枚举所有可能的参数到'Foo'并检查是否有任何'Foo :: Bar'匹配提供的'T'是一样的。另外,'template void f(typename Foo :: bar){}'是同一种不可诱发的上下文,你必须手动指定'T'来调用这个函数。 (顺便说一句,这是如何指定类模板的部分专业化。) – Xeo

+0

谢谢,你的解释是有道理的。现在的问题是构建一个解决方法。 – GRedner

回答

1

的问题是,T名称类型Foo<T>::Bar的一部分,但它不是类型的结构的一部分。

一个可能的解决方案是在类型的结构编码T

template<typename Outer, typename Inner> struct Nested: public Inner { 
    using Inner::Inner; 
}; 
template<typename T> struct Foo { 
    struct BarImpl { 
    int data; 
    }; 
    using Bar = Nested<Foo<T>, BarImpl>; 
}; 

template <typename T> struct is_bar: std::false_type {}; 
template <typename T, typename U> struct is_bar<Nested<Foo<T>, U>>: 
    std::is_same<typename Foo<T>::Bar, Nested<Foo<T>, U>> {}; 

测试:

static_assert(is_bar<Foo<int>::Bar>::value, "!"); 
static_assert(!is_bar<Foo<int>>::value, "!"); 
static_assert(!is_bar<int>::value, "!"); 
+0

这很聪明 - 可能太聪明了。我担心任何人对此代码进行维护(阅读:将来我)将无法解开它。我有一个使用boost :: tti的替代解决方案,但是我的名声很低,以至于我在8小时内回答自己的问题。所以你们都必须等到今晚:) – GRedner

0

编译器是正确的,简单的,容易理解的解释是:他们只是不想替换所有可能的类型T只是为了实现在给定模板内部是否存在嵌套类型栏。更精确的解释,你可能会发现在一个'经典'(和我所知的希望)有关模板的书:“C++模板 - 完整指南”

幸运的是,C++ 11可以帮助您做得更好! :)

#include <type_traits> 

template <typename T> 
struct has_nested_bar 
{ 
    template <typename W> 
    struct wrapper {}; 

    template <typename C> 
    static std::true_type check(
     const wrapper<C>* 
     , const typename C::Bar* = nullptr 
    ); 

    template <class C> 
    static std::false_type check(...); 

    constexpr static bool value = std::is_same< 
     decltype(check<T>(nullptr)) 
     , std::true_type 
     >::type::value; 
    typedef std::integral_constant<bool, value> type; 
}; 

这metafucntion将检查一个给定类型嵌套了Bar型(据我understant这是你is_bar的初始purpise)。

template <typename T> 
struct Foo 
{ 
    struct Bar 
    { 
     int data; 
    }; 
}; 

struct Bar {}; 

int main() 
{ 
    std::cout << has_nested_bar<Foo<int>>::value << std::endl; 
    std::cout << has_nested_bar<Bar>::value << std::endl; 
    return 0; 
} 

将输出:

[email protected] /work/tests $ ./has-nested-bar 
1 
0 

后,你可以在此与元函数您is_foo联合检查嵌套Bar实际上是一个Foo内...

+0

目的是为了测试一个类型*是否是嵌套的Bar,而不是它是否有*。 – Xeo

+0

@zaufi - 谢谢,但是Xeo说这不是我要找的。不过,我的“丑陋”解决方案使用这种类型的实用程序。 – GRedner

1

这里是一个可怕不雅的解决方案我自己的问题,使用TTI(http://svn.boost。组织/ SVN /升压/沙/ TTI):

首先,一个虚拟的标签添加到酒吧:

template <typename T> 
struct Foo 
{ 
    struct Bar 
    { 
    typedef void i_am_bar; 
    int data; 
    }; 
}; 

接下来,使用TTI以检查标签:

BOOST_TTI_HAS_TYPE(i_am_bar); 

template <typename T> 
struct is_bar : boost::tti::has_type_i_am_bar<T> 
{}; 
... 
BOOST_MPL_ASSERT((is_bar<Foo<int>::Bar>)); 
BOOST_MPL_ASSERT_NOT((is_bar<Foo<int> >)); 
BOOST_MPL_ASSERT_NOT((is_bar<int>)); 

难吃到可以肯定,但它满足我的用例。

+0

你真的不需要Boost.TTI,编写一个检查嵌套typedef是否存在的特性[相对容易](http://stackoverflow.com/a/3980926/500104)('has_element_type'结构)。尽管如此,找到一种解决方法仍然不错。 – Xeo