【问题标题】:Template specialization for an empty parameter pack空参数包的模板特化
【发布时间】:2011-09-19 23:55:12
【问题描述】:

我有一个可变参数模板函数,它调用自身来确定列表中的最大数字(由模板化参数构成)。我正在尝试对参数包为空时进行专门化,因此我可以只返回列表前面的数字,但我不知道该怎么做。我刚刚开始熟悉可变参数模板和模板专业化,但这是我目前所拥有的:

#include <string>
#include <iostream>

using namespace std;

template <int N, int... N2>
int tmax() {
    return N > tmax<N2...>() ? N : tmax<N2...>();
}

template <int N>
int tmax() {
    return N;
}

int main() {
    cout << tmax<32, 43, 54, 12, 23, 34>();
}

但是,这会产生以下错误:

test.cpp: In function ‘int tmax() [with int N = 34, int ...N2 = {}]’:
test.cpp:9:45:   instantiated from ‘int tmax() [with int N = 23, int ...N2 = {34}]’
test.cpp:9:45:   instantiated from ‘int tmax() [with int N = 12, int ...N2 = {23, 34}]’
test.cpp:9:45:   instantiated from ‘int tmax() [with int N = 54, int ...N2 = {12, 23, 34}]’
test.cpp:9:45:   instantiated from ‘int tmax() [with int N = 43, int ...N2 = {54, 12, 23, 34}]’
test.cpp:9:45:   instantiated from ‘int tmax() [with int N = 32, int ...N2 = {43, 54, 12, 23, 34}]’
test.cpp:18:39:   instantiated from here
test.cpp:9:45: error: no matching function for call to ‘tmax()’
test.cpp:9:45: error: no matching function for call to ‘tmax()’

我也试过这个,只是想看看它是否会起作用(尽管它会随机地将数字 0 引入列表,因此它永远不会返回小于 0 的数字):

template <int N, int... N2>
int tmax() {
    return N > tmax<N2...>() ? N : tmax<N2...>();
}

template <>
int tmax<>() {
    return 0;
}

但是,除了上面提到的错误,我得到这个错误:

error: template-id ‘tmax<>’ for ‘int tmax()’ does not match any template declaration

那么我应该怎么做才能让它工作呢?

我正在使用带有 -std=c++0x 标志的 g++ 4.5.2。

【问题讨论】:

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


    【解决方案1】:

    就个人而言,我更喜欢使用静态类成员而不是函数:

    template <int... N> struct max;
    template <int N, int... M> struct max<N, M...> {
      static const int value = max<N, max<M...>::value>::value;
    };    
    template <int N, int M> struct max<N, M> {
      static const int value = N > M ? N : M;
    };
    
    int main()
    {
      return max<1,2,3>::value;
    }
    

    更新:使用 ildjarn 的建议,这里是不那么冗长的版本:

    #include <type_traits>
    template <int... N> struct max;
    template <int N, int... M> struct max<N, M...>
      : std::integral_constant<int, max<N, max<M...>::value>::value> { };
    template <int N, int M> struct max<N, M>
      : std::integral_constant<int, (N > M ? N : M)> { };
    

    【讨论】:

    • +1,虽然我个人会从 std::integral_constant 派生而不是手动声明 value
    • @ildjarn:谢谢,更新了!保持简洁总是好的:-)
    • 怎么样:template&lt;int...&gt; struct max : integral_constant&lt;int, INT_MIN&gt; {}; template&lt;int a, int... x&gt; struct max&lt;a, x...&gt; : integral_constant&lt;int, (a &gt; max&lt;x...&gt;::value ? a : max&lt;x...&gt;::value)&gt; {};
    【解决方案2】:

    我看到两个使用 clang 的错误。

    1. 将采用单个 int 的重载放在首位。

    2. 使长度为 1 的列表明确无误。回想一下,可变参数列表的大小可以为零,当它们这样做时,在我看来您有歧义。

    这对我来说可以正确编译和运行:

    #include <iostream>
    
    using namespace std;
    
    template <int N>
    int tmax() {
        return N;
    }
    
    template <int N, int N1, int... N2>
    int tmax() {
        return N > tmax<N1, N2...>() ? N : tmax<N1, N2...>();
    }
    
    int main() {
        cout << tmax<32, 43, 54, 12, 23, 34>();
    }
    

    54

    【讨论】:

    • 以头/尾方式显式地“拆分”参数包的需要已经困扰了我好几次了,我希望我们会习惯它......但我不认为将基本情况放在首位是强制性的,因为它是我通常在之后立即放置的。
    【解决方案3】:

    由于你不能部分特化函数,你需要包装你的函数:

    template<int Head, int... Tail>
    struct Tmax{
      static int do(){
        return Head > Tmax<Tail...>::do() ? Head : Tmax<Tail...>::do();
      }
    };
    
    template<int N>
    struct Tmax<N>{
      static int do(){
        return N;
      }
    };
    
    template<int... Numbers>
    int tmax(){
      return Tmax<Numbers...>::do();
    }
    

    【讨论】:

    • 不确定它是否合法,但 g++-4.5.1 似乎不喜欢你的回答:ideone.com/VXqHv 手头没有我的标准副本,所以不确定这是否是一个真正的问题或旧的编译器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-19
    • 1970-01-01
    • 1970-01-01
    • 2011-06-10
    • 1970-01-01
    • 1970-01-01
    • 2011-05-10
    相关资源
    最近更新 更多