[英]Variadic functions addition in c++ with constrained types
我的目標是簡單添加任意數量的參數,只要它們具有以下類型-
整數(例如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?
如果(type == typeid(int).name())返回stoi(t);
如果我不這樣做,只調用return t
,則在調用函數時會出錯。
Cannot initialize return object of type 'int' with an lvalue of type 'const char *'
當我已經指定如果類型為整數時返回整數,這對我來說就沒有意義。
即使我確實return stoi(t)
(首先我也不明白為什么需要這樣做),並且如果類型為const char*
則return atoi(t)
,然后在開頭插入“ japan”或“ 123”或在模板arg列表的中間 [例如, func(1,2,2.5000,"123",12);
]使代碼此時抱怨。
int sum = t;
錯誤與上面相同。
Cannot initialize return object of type 'int' with an lvalue of type 'const char *'
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,我們還需要添加一個char重載0:
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;}
超載是一種可能性。 您也可以使用一些模板魔術來做到這一點。 這樣做的好處是,在編譯時會從所有不兼容的類型中修剪要累加的列表(最后一個元素除外,如果最后一個元素不匹配,則將其替換為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 );
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.