C ++ 11个可变数量的参数,相同的特定types
问题很简单,我将如何实现一个采用可变数量参数的函数(类似于可变参数模板),但是所有参数都具有相同的types,比如int。
我在想这件事情,
void func(int... Arguments)
或者不会对types工作recursion静态断言?
一个可能的解决scheme是使参数types成为一个容器,可以使用大括号初始值设定项列表(例如std::initializer_list<int>
或std::vector<int>
std::initializer_list<int>
。 例如 :
#include <iostream> #include <initializer_list> void func(std::initializer_list<int> a_args) { for (auto i: a_args) std::cout << i << '\n'; } int main() { func({4, 7}); func({4, 7, 12, 14}); }
这里是一个从重载集合中删除函数的版本,而不是给出一个static_assert。 这可以让你在types不完全相同的时候提供可以使用的函数的其他重载,而不是一个无法避免的致命的static_assert。
#include <type_traits> template<typename... T> struct all_same : std::false_type { }; template<> struct all_same<> : std::true_type { }; template<typename T> struct all_same<T> : std::true_type { }; template<typename T, typename... Ts> struct all_same<T, T, Ts...> : all_same<T, Ts...> { }; template<typename... T> typename std::enable_if<all_same<T...>::value, void>::type func(T...) { }
如果你想支持完美的转发,你可能希望在检查types之前先衰减types,这样只要它们具有相同的types,函数就会接受左值和右值参数的混合:
template<typename... T> typename std::enable_if<all_same<typename std::decay<T>::type...>::value, void>::type func(T&&...) { }
另外,如果你有一个testing逻辑连接的通用特性,你可以使用std::is_same
来代替编写自己的all_same
:
template<typename T, typename... Ts> typename std::enable_if<and_<is_same<T, Ts>...>::value, void>::type func(T&&, Ts&&...) { }
因为这需要至less一个参数,所以还需要另一个重载来支持零参数的情况:
void func() { }
and_
helper可以这样定义:
template<typename...> struct and_; template<> struct and_<> : public std::true_type { }; template<typename B1> struct and_<B1> : public B1 { }; template<typename B1, typename B2> struct and_<B1, B2> : public std::conditional<B1::value, B2, B1>::type { }; template<typename B1, typename B2, typename B3, typename... Bn> struct and_<B1, B2, B3, Bn...> : public std::conditional<B1::value, and_<B2, B3, Bn...>, B1>::type { };
我认为你可以通过指定一个具体的types来咀嚼参数包的参数。 就像是:
class MyClass{}; class MyOtherClass{}; void func() { // do something } template< typename... Arguments > void func( MyClass arg, Arguments ... args ) { // do something with arg func( args... ); // do something more with arg } void main() { MyClass a, b, c; MyOtherClass d; int i; float f; func( a, b, c ); // compiles fine func( i, f, d ); // cannot convert }
在通用的情况下, void func( MyClass arg, Arguments ... args )
将会变成void func( arg, Arguments ... args )
和模板typesT.
@Skeen这个怎么样?
template <typename T> void func_1(std::initializer_list<T>&& a) { // do something } template <typename... T> void func(T&&... a) { func_1({std::forward<T>(a)...}); } int main() { func(1, 2, 3); // func(1, 2, 3, 4.0); // OK doesn't compile }
如果你不想使用基于大括号的initializer_list
/ vector
并且想要将参数以参数包的forms分开,那么下面的解决scheme会在编译时使用recursionstatic_assert
来检查它:
#include<type_traits> template<typename T1, typename T2, typename... Error> struct is_same : std::false_type {}; template<typename T, typename... Checking> struct is_same<T, T, Checking...> : is_same<T, Checking...> {}; template<typename T> struct is_same<T,T> : std::true_type {}; template<typename... LeftMost> void func (LeftMost&&... args) { static_assert(is_same<typename std::decay<LeftMost>::type...>::value, "All types are not same as 'LeftMost'"); // ... } int main () { int var = 2; func(1,var,3,4,5); // ok func(1,2,3,4.0,5); // error due to `static_assert` failure }
实际上,这个解决scheme将会检查所有关于第一个参数的参数。 假设它是double
那么一切都将被检查对double
。
因为我不认为我看到这个解决scheme,所以你可以为每个types(在你的情况下,只是int
)编写一个特定的函数,然后是一个采用可变参数types的转发函数。
写每个特定的情况:
那么对于每个特定的情况:
// only int in your case void func(int i){ std::cout << "int i = " << i << std::endl; }
那么你的转发function是这样的:
template<typename Arg0, typename Arg1 typename ... Args> void func(Arg0 &&arg0, Arg1 &&arg1, Args &&... args){ func(std::forward<Arg0>(arg0)); func(std::forward<Arg1>(arg1), std::forward<Args>(args)...); }
这很好,因为它可以扩展,当你想要接受也许另一种types。
像这样使用:
int main(){ func(1, 2, 3, 4); // works fine func(1.0f, 2.0f, 3.0f, 4.0f); // compile error, no func(float) }