具有模板模板参数的类模板专业化

时间:2018-01-17 04:13:06

标签: c++ c++11 templates

我试图在类型s.t上专门化一个类。它忽略了给定类型的常量。在这种情况下,类型是模板模板参数:

template <class T, typename Enable = void>
struct bar 
{
    bar()
    {
        static_assert(!std::is_same<T,T>::value, "no implementation of bar for type T");
    }
};

template <template <typename> class FooType, class T>
struct bar<FooType<T>, typename std::enable_if<std::is_same<typename std::remove_cv<FooType<T>>::type, foo<T>>::value>::type>
{};

上面的代码在GCC 4.8.4和clang 5.0(带-std = c ++ 11)中都抱怨,当与匹配FooType的模板参数化的类一起使用时,bar是未定义的。即使我删除了sfinae参数,仍无法找到专门化。

可以在此处找到此问题的示例:https://godbolt.org/g/Cjci9C。 在上面的例子中,specialization的构造函数有一个静态断言,当与const FooType一起使用时,即使sfinae参数被硬编码为void也是如此。当与非const FooType一起使用时,所有工作都按预期工作。

有人可以提供一个解释,说明为什么constness在这种情况下禁止类型扣除(匹配?)。

编辑(更新代码):

这是一个完全可编译的代码段。我试图捕获此代码段中的最小示例。原始链接已更新,以反映此示例。

#include <assert.h>
#include <type_traits>

template <class T>
struct foo {};

template <class T, typename Enable = void>
struct bar 
{
    bar()
    {
        static_assert(!std::is_same<T,T>::value, "no implementation of bar for type T");
    }
};

template <template <typename> class FooType, class T>
struct bar<FooType<T>, typename std::enable_if<std::is_same<typename std::remove_cv<FooType<T>>::type, foo<T>>::value>::type>
{};

int main()
{
  bar<foo<int>> mut_foo; // This is fine.
 // bar<const foo<int>> const_foo; // Error. No implementation found.
}

删除main的第二行上的注释会触发静态断言。我也尝试过std :: decay和std :: remove_const但没有成功。

编辑(非重复理由):

虽然链接问题确实会引发类似问题,但它不需要使用模板模板参数。它还仅提供了解决问题的技术,并没有证明为什么给定的代码片段不起作用。有趣的是,该技术似乎不适用于模板模板参数,因为将以下代码段替换为上述示例会导致相同的错误:

template <template <typename> class FooType, class T>
struct bar<FooType<T>,
           typename std::enable_if<std::is_same<FooType<T>, foo<T>>::value || std::is_same<FooType<T>, const foo<T>>::value>::type>
{};

1 个答案:

答案 0 :(得分:1)

const foo<int>不匹配FooType<T>
它会匹配const FooType<T>T(或const T)。

专业化匹配后,您可以添加SFINAE:

所以,在你的情况下,你可能会这样做

template <typename T> struct is_foo : std::false_type {};
template <typename T> struct is_foo<foo<T>> : std::true_type {};


template <class T>
struct bar<T,
           typename std::enable_if<is_foo<typename std::remove_cv<T>::type>::value>::type>
{};