具有模板模板参数的类模板特化

3

我正在尝试将一个类专门化为一种类型,使其忽略给定类型的const属性。在这种情况下,该类型是模板模板参数:

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

以上代码在使用与FooType模板参数化匹配的类时,在GCC 4.8.4和clang 5.0(使用-std=c++11)中均会报错,指出bar未定义。即使我删除了sfinae参数,专门化仍然无法找到。
这个问题的示例可以在这里找到:https://godbolt.org/g/Cjci9C。 在上面的示例中,专门化的构造函数具有一个静态断言,当与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>
{};

这个示例中,为bar<const FooType<T,U>>添加一个新的特化将匹配第二个示例。我猜这就是规则,但我不是100%确定。 - Francisco Gallego Salido
2
看起来这个是你的最小示例。 - n. m.
可能是Const and non const template specialization的重复问题。 - Francisco Gallego Salido
@JiveDadson 我已经更新了示例,包含一个完全可编译的代码片段。 - mgoldman
@n.m. 我不相信你提供的链接示例提供了正确的特性。我不认为该示例能够正常工作,因为模板“base”是针对非const Q进行专门化的。这个示例有趣的地方在于模板模板参数和使用SFINAE来约束它。 - mgoldman
显示剩余9条评论
1个回答

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

如果我理解正确的话,除了类型特征或相关类型,没有其他方式可以推导出FooType模板参数化的方法? - mgoldman
我不确定我理解你的意思,但是你可以实现 is_same_template<FooType, foo>(但要注意别名)和 template_element<I, FooType<T>>::type(类似于 tuple_element),或者使用部分特化,就像你尝试过的 bar 一样,但是你的方法无法处理 cv_限定符。 - Jarod42
你能指出标准中有关这种特化模式匹配的相关语言吗? - mgoldman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接