请考虑以下代码:
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;与基本案例一起被优化。然而,它看起来有点像黑客。
答案 0 :(得分:2)
让可变参数版本至少采用三种固定类型模板参数:
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...>( );
}
如果包的大小等于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...>( );
}
答案 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...>( );
}