【问题标题】:How to specialize a template with template-tempate parameters如何使用模板模板参数专门化模板
【发布时间】:2015-03-13 09:11:29
【问题描述】:

最后编辑

我有一个带有模板的函数:

template <template <typename ...> class P, typename ... Args>
void f(const P<Args...> &p)
{
    std::cout << "Template with " << sizeof...(Args) << " parameters!\n";
}

到目前为止,它适用于我测试过的任何类型的模板:

f(std::valarray<int>{});    // Prints: "Template with 1 parameters!"
f(std::pair<char, char>{}); // Prints: "Template with 2 parameters!"
f(std::set<float>{});       // Prints: "Template with 3 parameters!"
f(std::map<int, int>{});    // Prints: "Template with 4 parameters!"

但是,假设我想对模板进行专门化,因为它需要一个带有两个参数的模板,下面的代码不起作用:

template <>
void f<template <typename, typename> class P, typename A, typename B>(const P<A, B> &p)
{
    std::cout << "Special case!\n";
}

parse error in template argument list
 void f<template <typename, typename> class P, typename A, typename B>(const P<Args...> &p) { std::cout << "Template with " << sizeof...(Args) << " parameters!\n"; }
      ^
'P' does not name a type
 void f<template <typename, typename> class P, typename A, typename B>(const P<Args...> &p) { std::cout << "Template with " << sizeof...(Args) << " parameters!\n"; }
                                                                             ^
expected ',' or '...' before '<' token
 void f<template <typename, typename> class P, typename A, typename B>(const P<Args...> &p) { std::cout << "Template with " << sizeof...(Args) << " parameters!\n"; }
                                                                              ^
template-id 'f<<expression error> >' for 'void f(int)' does not match any template declaration
 void f<template <typename, typename> class P, typename A, typename B>(const P<Args...> &p) { std::cout << "Template with " << sizeof...(Args) << " parameters!\n"; }

AFAIK 使用其他类型的模板参数非常简单:

// Type parameter
template <typename TYPE>
void f(TYPE) { std::cout << "Type!\n"; }

// Non-type parameter
template <int VALUE>
void f() { std::cout << "Value " << VALUE << "!\n"; }

// Type parameter specialization
template <>
void f(float) { std::cout << "Special type case!\n"; }

// Non-type parameter specialization
template <>
void f<666>() { static_assert(false, "Forbidden number!"); }

如何使用模板-模板模板实现此功能?

编辑:

正如orlpangew 所指出的,函数模板不能部分特化,所以我应该坚持对象模板here is my attempt

template <template <typename ...> class P, typename ... Args>
struct c
{
    using type = P<Args...>; 
    const std::size_t count = sizeof...(Args);

    void f(const type &t)
    {
        std::cout << "Template with " << sizeof...(Args) << " parameters!\n";
    }
};

template <template <typename, typename> class P, typename A, typename B>
struct c<P, A, B> 
{
    using type = P<A, B>; 

    void f(const type &t)
    {
        std::cout << "Spezialized 2 parameters!\n";
    }
};

有效:

c<std::valarray, int>                    c_valarray_int;
c<std::pair, int, char>                  c_pair_int_char;
c<std::vector, int, std::allocator<int>> c_vector_int;
c<std::map, int, int>                    c_map_int_int;

c_valarray_int.f({});  // Prints: "Template with 1 parameters!"
c_pair_int_char.f({}); // Prints: "Spezialized with 2 parameters!"
c_vector_int.f({});    // Prints: "Spezialized with 2 parameters!"
c_map_int_int.f({});   // Prints: "Template with 2 parameters!" (expected)

但是现在,我应该指定所有参数,而不是让编译器猜测整个事情,嗯……这不是悲剧。

【问题讨论】:

标签: c++ template-specialization template-templates


【解决方案1】:

您正在尝试 部分 特化您的函数模板——特化 any 具有两个模板参数的模板。这在 C++ 中是不允许的。函数模板不能部分特化。

换一种方式看:您为模板类型参数和模板非类型参数显示的显式特化使用具体参数。要明确专门化您的函数模板,您可以执行以下操作:

template <>
void f<std::pair, int, double>(const std::pair<int, double> &p)
{
    std::cout << "Special case!\n";
}

在您的原始代码中,PAB 仍然是“未绑定的”——它们是参数,而不是参数。显式特化不能有模板参数;被特化的主模板的所有模板参数都必须绑定到该特化提供的具体参数。


解决您的编辑问题:您仍然可以通过参数推导保留函数模板接口,并简单地将调用转发到(可能部分专门化的)类模板,如下所示:

template <template <typename ...> class P, typename ... Args>
struct c
{
    using type = P<Args...>; 
    static const std::size_t count = sizeof...(Args);

    static void f(const type &t)
    {
        std::cout << "Template with " << sizeof...(Args) << " parameters!\n";
    }
};

template <template <typename, typename> class P, typename A, typename B>
struct c<P, A, B> 
{
    using type = P<A, B>; 

    static void f(const type &t)
    {
        std::cout << "Spezialized 2 parameters!\n";
    }
};

template <template <class ...> class P, class... Args>
void f(const P<Args...> &t)
{
    c<P, Args...>::f(t);
}

[Live example]

【讨论】:

  • 那么,问题在于模板模板版本是部分特化,而类型和非类型版本是全部特化?
  • @PaperBirdMaster 差不多。我已经扩展了答案。
  • 惊人的@Angew!多谢。顺便说一句:coliru 链接向我显示了一个空白页面,但我已经对其进行了测试,谢谢。
  • @PaperBirdMaster 嗯,该链接对我有用。无论如何,它只是添加到答案中的代码中的 4 个原始调用(来自您问题中的第二个代码 sn-p)。
【解决方案2】:

好吧,做你想做的事情的正确语法是这样的:

template <template<typename, typename> class P, typename A, typename B>
void f<P, A, B>(const P<A, B> &p) {
    std::cout << "Special case!\n";
}

但是,这是部分特化,在函数上是不允许的。不过,您可以将您的函数转换为具有静态方法的类,并使用包装函数调用该类的静态方法。

【讨论】:

  • 我遇到了您的修复问题(请参阅here)可变参数结构与专用结构冲突
  • @PaperBirdMaster 我已经从我的答案中删除了这个例子,但我现在不想写一个工作例子。
  • 很抱歉打扰你@orlp 我只是在尝试你的解决方案,我很抱歉。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多