是否可以为可变参数成员函数模板设置两个参数基础案例?

时间:2015-08-12 14:09:59

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

请考虑以下代码:

class Foo {
public:
    template<typename X, typename T, typename ... Args> static void f( );
    //template<typename X, typename T> static void f( );
    template<typename X> static void f( );
};

template<typename X> void Foo::f( ) {
    cout << "Swallowed the last argument." << endl;
}

/*
template<typename X, typename T> void Foo::f( ) {
    cout << "Swallowed last two arguments." << endl;
}
 */

template<typename X, typename T, typename ... Args> void Foo::f( ) {
    cout << sizeof (T ) << endl;
    Foo::f <X, Args...>( );
}


...
    Foo::f<void*, int, double, long>( );
...

这很好用,输出是:

4
8
8
Swallowed the last argument.

但是在我正在处理的具体问题中,我想在之前的某个级别停止递归,如注释掉的代码所示。当这些行没有被注释掉时,我得到了错误(gcc 4.8.3):

g++ -Wall -std=c++1y -march=native -fmessage-length=0 -Wno-multichar   -g  -c -o obj/OneOff/OneOff.o OneOff/OneOff.cpp
OneOff/OneOff.cpp: In instantiation of ‘static void Foo::f() [with X = void*; T = double; Args = {long int}]’:
OneOff/OneOff.cpp:132:23:   required from ‘static void Foo::f() [with X = void*; T = int; Args = {double, long int}]’
OneOff/OneOff.cpp:137:36:   required from here
OneOff/OneOff.cpp:132:23: error: call of overloaded ‘f()’ is ambiguous
  Foo::f <X, Args...>( );
                       ^
OneOff/OneOff.cpp:132:23: note: candidates are:
OneOff/OneOff.cpp:130:58: note: static void Foo::f() [with X = void*; T = long int; Args = {}]
 template<typename X, typename T, typename ... Args> void Foo::f( ) {
                                                          ^
OneOff/OneOff.cpp:125:39: note: static void Foo::f() [with X = void*; T = long int]
 template<typename X, typename T> void Foo::f( ) {
                                       ^
gmake: *** [obj/OneOff/OneOff.o] Error 1

是否有可能以某种方式告诉编译器两个参数版本是特化/基本情况。例如。使用像&lt; ..,typename Args = {}&gt;?

我找到的另一个选择是将f()更改为:

template<typename X, typename T, typename ... Args> void Foo::f( ) {
    cout << sizeof (T ) << endl;
    if ( sizeof ...( Args ) > 1 ) {
        Foo::f <X, Args...>( );
    } else {
        cout << "Swallowed last two arguments." << endl;
    }
}

这给出了期望的结果,并且可能一旦产生个体变化,如果... elses&#39;与基本案例一起被优化。然而,它看起来有点像黑客。

2 个答案:

答案 0 :(得分:2)

选项#1

让可变参数版本至少采用三种固定类型模板参数:

template <typename X, typename T, typename V, typename... Args>
static void f();

// ...

template <typename X, typename T, typename V, typename... Args>
void Foo::f()
{
    Foo::f<X, V, Args...>( );
}

DEMO 1

选项#2

如果包的大小等于0,则使用SFINAE禁用可变版本:

#include <type_traits>

template <typename X, typename T, typename... Args>
static auto f()
    -> typename std::enable_if<(sizeof...(Args) > 0)>::type;

//...

template <typename X, typename T, typename... Args>
auto Foo::f()
    -> typename std::enable_if<(sizeof...(Args) > 0)>::type
{
    Foo::f<X, Args...>( );
}

DEMO 2

答案 1 :(得分:1)

一个非常简单的选择是在递归的情况下添加一个额外的模板参数,这样只有在至少有三个参数时才选择它:

class Foo {
public:
    template<typename X, typename T, typename U, typename ... Args> static void f( );
    template<typename X, typename T> static void f( );
};


template<typename X, typename T> void Foo::f( ) {
    cout << "Swallowed last two arguments." << endl;
}

template<typename X, typename T, typename U, typename ... Args> void Foo::f( ) {
    cout << sizeof (T ) << endl;
    Foo::f <X, U, Args...>( );
}

Live demo