我的目标是只需添加任何数量的参数,只要它们属于以下类型 -
整数(例如123)
字符串表示为整数(例如" 123")
如果它们属于其他类型,我会忽略它们。
方法
这就是我认为代码的样子 -
// BASE
template <typename T>
int func(T t)
{
string type= typeid(t).name();
if (type==typeid(int).name())
return stoi(t);
else if (type==typeid(const char*).name())
return atoi(t);
else
return 0;
}
// RECUR
template<typename T, typename... Args>
int func(T t, Args... args) // recursive variadic function
{
string type = typeid(t).name();
if (type==typeid(int).name()){
int sum = t;
return sum+func(args...);
}
else
return func(args...);
}
// MAIN
int main()
{
// All testing here in MAIN.
// [2]
int funcres = func('a',1, 2.5000,"123");
cout << funcres << endl;
return 0;
}
这给了我预期的答案: 124。
然而, 我做了以下观察,告诉我我的代码不是故障安全的。
为什么在这个基函数的行中需要stoi?
if(type == typeid(int).name()) return stoi(t);
如果我不这样做并只调用return t
,则在调用我的函数时会出错。
Cannot initialize return object of type 'int' with an lvalue of type 'const char *'
当我已经指定在类型为整数时返回整数时,这对我没有意义。
即使我做return stoi(t)
(我不明白为什么一开始就需要这样做),如果类型为return atoi(t)
,则const char*
然后插入&#34;日本&#34;或&#34; 123&#34;模板arg列表[for.e.g func(1,2,2.5000,"123",12);
]中的开头或位于中间导致代码在此时进行投诉。
int sum = t;
错误与上述相同。
Cannot initialize return object of type 'int' with an lvalue of type 'const char *'
答案 0 :(得分:2)
C ++模板是静态解析的,这意味着替换参数必须适用于所有替换,甚至是那些在运行时无法访问的替换。但是,通过使用带辅助函数的重载而不是RTTI,我们可以更清晰地处理转换:
template<class T>
int forceInt(T arg) { return 0; }
int forceInt(int arg) { return arg; }
int forceInt(std::string arg) { return std::stoi(arg); }
int forceInt(const char * arg) { return std::stoi(arg); }
使用此辅助函数,您可以执行简单的递归求和:
int func() { return 0; }
template<typename T, typename... Args>
int func(T t, Args... args) // recursive variadic function
{
return forceInt(t) + func(args...);
}
这也可以扩展为处理任何整数类型。通过在一般重载上使用SFINAE将其限制为非整数类型,这会导致int重载成为整数类型的首选。但是char是不可变的,所以如果你不想将它隐式转换为int,我们还需要添加0的char重载:
template<class T, class U = typename std::enable_if<!std::is_integral<T>::value>::type>
int forceInt(T arg) { return 0; }
int forceInt(char arg) {return 0;}
答案 1 :(得分:1)
重载是一种可能性。你也可以用一些模板魔术来做到这一点。这样做的好处是,您在求和的列表将在编译时从所有不兼容的类型中删除(除了最后一个元素,如果不匹配则替换为0)。
#include <cassert>
#include <string>
#include <type_traits>
template < typename T >
struct is_const_char : std::false_type {};
template < >
struct is_const_char < const char * > : std::true_type {};
template < typename T >
struct is_int : std::false_type {};
template < >
struct is_int < int > : std::true_type {};
// Break condition
template < typename T >
typename std::enable_if<is_int<T>::value, int>::type
sum(T t)
{
return t;
}
template < typename T >
typename std::enable_if<is_const_char<T>::value, int>::type
sum(T t)
{
return std::stoi(t);
}
template < typename T >
typename std::enable_if<!is_int<T>::value && !is_const_char<T>::value, int>::type
sum(T)
{
return 0;
}
// Forward declarations
template < typename T, typename ... Args >
typename std::enable_if<is_const_char<T>::value, int>::type
sum(T, Args ...);
template < typename T, typename ... Args >
typename std::enable_if<is_int<T>::value, int>::type
sum(T, Args ...);
// Recursions
template < typename T, typename ... Args >
typename std::enable_if<!is_int<T>::value && !is_const_char<T>::value, int>::type
sum(T, Args ... args)
{
return sum(args...);
}
template < typename T, typename ... Args >
typename std::enable_if<is_int<T>::value, int>::type
sum(T t, Args ... args)
{
return t + sum(args...);
}
template < typename T, typename ... Args >
typename std::enable_if<is_const_char<T>::value, int>::type
sum(T t, Args ... args)
{
return std::stoi(t) + sum(args...);
}
// Test it
int main()
{
assert( sum('a', 1, 2, 3, "123", 4, 5) == 138 );
assert( sum('a',1, 2.5000,"123") == 124 );
}