C++ 11可变数量的参数,相同的特定类型

Ske*_*een 45 c++ variadic c++11

问题很简单,我如何实现一个带有可变数量参数的函数(类似于可变参数模板),但是所有参数都具有相同的类型,比如说int.

我正在考虑类似的东西;

void func(int... Arguments)
Run Code Online (Sandbox Code Playgroud)

或者,类型的递归静态断言不起作用吗?

hmj*_*mjd 47

一种可能的解决方案是使参数类型成为可以通过大括号初始化列表初始化的容器,例如std::initializer_list<int>std::vector<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});
}
Run Code Online (Sandbox Code Playgroud)


Jon*_*ely 18

这是一个从重载集中删除函数的版本,而不是给出static_assert.这允许您提供在类型不完全相同时可以使用的函数的其他重载,而不是无法避免的致命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...)
{ }
Run Code Online (Sandbox Code Playgroud)

如果你想支持完美的转发,你可能想在检查之前衰减类型,这样只要它们具有相同的类型,函数就会接受lvalue和rvalue参数的混合:

template<typename... T>
typename std::enable_if<all_same<typename std::decay<T>::type...>::value, void>::type
func(T&&...)
{ }
Run Code Online (Sandbox Code Playgroud)

或者,如果你有一个测试逻辑连接的通用特性,你可以使用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&&...)
{ }
Run Code Online (Sandbox Code Playgroud)

因为这需要至少一个参数,你还需要另一个重载来支持零参数的情况:

void func() { }
Run Code Online (Sandbox Code Playgroud)

and_助手可以定义如下所示:

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
  { };
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是,这与假定的`func(Foo ... foos)`不是100%相同,因为如果`Foo`具有非显式的构造函数,则`func({x,y,z})将不起作用-编译器无法推断`{x,y,z}`的类型,除非在`func`的签名中指定了该类型。 (2认同)

use*_*401 12

我认为你可以通过在从参数包中咀嚼你的参数时指定一个具体类型来做到这一点.就像是:

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
}
Run Code Online (Sandbox Code Playgroud)

在通用情况下void func( MyClass arg, Arguments ... args )void func( arg, Arguments ... args )使用模板类型T.


iam*_*ind 5

如果您不想使用基于大括号的initializer_list/vector并希望以参数包的形式将参数分开,那么下面的解决方案在编译时使用递归static_asserts进行检查:

#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
}
Run Code Online (Sandbox Code Playgroud)

实际上,此解决方案将检查与第一个参数有关的所有参数。假设double那时一切都会被检查double

  • 使用转发引用(`LeftMost&amp;&amp;`)意味着如果你用左值和右值的混合调用函数,静态断言将失败,例如`int i=0; func(i, 1);` 所以最好检查 `is_same&lt;typename std::decay&lt;LeftMost&gt;::type...&gt;`。 (3认同)

dus*_*tha 5

@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
}
Run Code Online (Sandbox Code Playgroud)