有没有办法定义相同类型的参数的可变参数数?
Is there a way to define a variadic number of arguments of the same type?
我不知道如何实现具有相同类型参数的可变数量的函数。
我正在为堆栈和内存很少的微控制器编写,所以我不能使用递归或 STL(有例外的部分)。
有没有可能做出这样的功能?
struct S{
int r1;
int r2;
};
template<S* s, int... args> fun(int arg1, int arg2);
它扩展到这样的内容:
for(int arg:args){
s->r1+=7*arg;
}
调用示例:
S s;
const int mode=3, speed=1;
fun<&s,1,2,7,4>(mode,speed);
对于C++20 概念,可能需要让可变参数包中的所有参数具有相同的类型。
不幸的是,截至 C++20 年,标准库没有all_same的概念(只有两种类型的std::same_as
),但它可以很容易地定义:
template<class... Ts>
concept all_same =
sizeof...(Ts) < 2 ||
std::conjunction_v<
std::is_same<std::tuple_element_t<0, std::tuple<Ts...>>, Ts>...
>;
template<typename... Ts> requires all_same<Ts...>
void foo(Ts&&... ts) {}
代码:https://godbolt.org/z/dH9t-N
请注意,在许多情况下,不需要相同的类型,而是要求所有参数都具有通用类型。若要要求通用类型,根据测试是否存在通用类型,可以具有以下概念:
template <typename AlwaysVoid, typename... Ts>
struct has_common_type_impl : std::false_type {};
template <typename... Ts>
struct has_common_type_impl<std::void_t<std::common_type_t<Ts...>>, Ts...>
: std::true_type {};
template <typename... Ts>
concept has_common_type =
sizeof...(Ts) < 2 ||
has_common_type_impl<void, Ts...>::value;
template<typename... Ts> requires has_common_type<Ts...>
void foo(Ts&&... ts) {}
代码:https://godbolt.org/z/5M6dLp
您可以使用折叠表达式(c++17) 和概念(c++20) 功能轻松完成此操作。
概念将如下所示:
template<typename T, typename... Types>
concept is_all_same = (... && std::is_same<T, Types>::value);
如果您希望它们只是相同的类型,则可以通过以下方式使用它:
template<typename... Types> requires is_all_same<Types...>
void fun();
如果希望函数采用特定类型,可以通过以下方式使用它:
template<is_all_same<int>... Types>
void fun();
我不知道如何实现具有相同类型参数的可变数量的函数。
相同类型的模板参数还是相同类型的普通函数参数?
第一种情况很简单(如果该类型是模板值类型的允许类型),与您编写的完全一样
template<S* s, int... args>
fun (int arg1, int arg2);
你可以使用模板折叠来使用它们,如果你可以使用C++17,
template <S* s, int... args>
auto fun (int arg1, int arg2)
{ ((s->r1 += 7 * args), ...); }
或者之前以更复杂的方式(C++11/C++14)
template <S* s, int... args>
auto fun (int arg1, int arg2)
{
using unused = int[];
(void)unused { 0, s->r1 += 7 * args ... };
}
不幸的是,您可以使用编译时已知的整数调用这种类型的函数,因此,例如,不使用变量
int a = 7;
fun<&s,1,2,a,4>(mode,speed); // compilation error
在这种情况下,您需要相同类型的普通函数参数的可变参数列表;不幸的是,这有点复杂。
您可以创建模板参数的典型可变参数列表
template <typename ... Args>
auto fun (Args ... args)
通过SFINAE,强加所有Args...
都被推导或解释为int
(见迈克尔·肯泽尔的回答)。
不幸的是,这要求每个参数都是如果类型int
,因此使用(通过示例)调用 funclong int
会给出编译错误
fun(1, 2, 3l); // compilation error (3l is a long int, not an int)
显然,你可以放宽SFINAE条件,强加(通过示例)所有Args...
类型都可以转换为(std::is_convertible
)到int
,但并不完全开发一个函数接收相同类型的可变参数数。
如果你可以接受参数数量的上限(在下面的示例中是64
),并且该函数是一个类的方法(可能是静态的),你可以创建一个foo
类,其中包含一个接收零int
的方法f()
,一个接收一个int
的f()
,一个接收两个int
的f()
, 等等,直到收到 63int
秒的f()
。
以下是完整的编译C++17示例
#include <utility>
#include <type_traits>
struct S
{
int r1;
int r2;
};
S s;
const int mode=3, speed=1;
template <typename T, std::size_t>
using getType = T;
template <std::size_t N, typename = std::make_index_sequence<N>>
struct bar;
template <std::size_t N, std::size_t ... Is>
struct bar<N, std::index_sequence<Is...>>
{
static constexpr auto f (getType<int, Is> ... args)
{ ((s.r1 += 7 * args), ...); }
};
template <S &, std::size_t N = 64u, typename = std::make_index_sequence<N>>
struct foo;
template <S & s, std::size_t N, std::size_t ... Is>
struct foo<s, N, std::index_sequence<Is...>> : public bar<Is>...
{ using bar<Is>::f...; };
int main ()
{
foo<s>::f(mode, speed);
}
在 C++14 中稍微复杂一些,因为没有可变参数using
所以你必须以递归的方式编写foo
类。
在 C++11 中,您还必须开发std::make_index_sequence
/std::index_sequence
的替代品。
遗憾的是,目前无法指定每个参数属于相同类型的函数参数包。您可以得到的下一个最好的东西(据我所知)是一个函数,它接受可变数量的任何类型的参数,只要它们的类型都int
:
#include <type_traits>
template <typename... Args>
auto f(Args... args) -> std::enable_if_t<(std::is_same_v<Args, int> && ...)>
{
…
}
void test()
{
f(1, 2, 3); // OK
f(1, 2, 3.0f); // error
}
现场示例在这里
这里的诀窍是依靠 SFINAE 有效地删除函数的所有版本,其中并非所有args
最终都是int
型......
对于您的具体示例,您可以这样做,例如:
#include <type_traits>
struct S
{
int r1;
int r2;
};
template <S& s, typename... Args>
auto f(Args... args) -> std::enable_if_t<(std::is_same_v<Args, int> && ...)>
{
((s.r1 += 7 * args), ...);
}
S s;
const int mode=3, speed=1;
void test()
{
f<s>(mode, speed);
}
现场演示在这里
具有多个参数的更多扩展示例。
从这个答案这里>有没有办法定义相同类型的参数的可变参数数?
较短的初始化 (std::is_same_v) 和使用>的示例
template<class T, class... Types>
concept is_all_same = (... && std::is_same_v<T, Types>);
// "requires" to prevent function instance without arguments
template<class... Types> requires is_all_same<Types...>
void fun1(const Types&... types)
{
for (const auto &t : {types...})
std::cout << t << std::endl;
}
template<is_all_same<int>... Types> requires is_all_same<Types...>
void fun2(const Types&... types)
{
for (const int &t : {types...})
std::cout << t << std::endl;
}
还有一些可用的例子
// check same type
template<class T, class... Types>
concept is_all_same = (... && std::is_same_v<T, Types>);
// different amount of arguments, different one type
template<class... Types> requires is_all_same<Types...>
void fun1(const Types&... types)
{
for (const auto &t : {types...})
std::cout << t << std::endl;
}
// different amount of arguments one type - const char*
template<is_all_same<const char*>... Types> requires is_all_same<Types...>
void fun2(const Types&... types)
{
for (const char *t : {types...})
std::cout << t << std::endl;
}
//
// check c-array of chars
template<class T, class... Types>
concept is_c_arr_char =
std::is_bounded_array_v<T> &&
std::is_same_v<std::remove_all_extents_t<T>, char> &&
(... && (
std::is_bounded_array_v<Types> &&
std::is_same_v<std::remove_all_extents_t<Types>, char>
));
// different amount of arguments
// different type based on "signature" c-array chars - const char[x]
template<class... Types> requires is_c_arr_char<Types...>
void fun3(const Types&... types)
{
for (const char *t : {types...})
std::cout << t << std::endl;
}
//
int main()
{
fun1(1.1, 2.2);
const char* a = "a1";
const char* b = "b22";
fun2(a, b);
fun2((const char*)"a1", (const char*)"b22");
fun3("c3", "d44");
const char c[] = "c3";
const char d[] = "d44";
fun3(c, d);
}
对我来说后果 - 最好使用"初始化列表" - 在那里我们看到 size() 函数 - 访问参数数量
const std::initializer_list<const char*> &args
- 在函数中使用 const int size 参数创建数组会在 Visual Studio 中抛出错误 C++:表达式的计
- 如何在模板函数中实例化其长度使用模板参数的数组
- 基于参数创建数组
- Pybind11 默认参数 numpy 数组或 None
- 有没有办法根据命令行参数定义数组大小?运行时与编译时实例化?
- 更改为参数的数组的值
- 根据 C++11 中的模板参数选择数组大小
- 是否可以使用C 函数中的const int参数创建数组
- 根据参数将数组分成 5 个不同的数组
- 你究竟如何通过函数的参数传递数组?
- 函数参数中数组大小未指定
- 数组作为函数参数查找数组长度时出错
- 如何使用函数参数设置数组大小
- 可变参数模板数组调用未定义的行为
- 提升 1.55,而 13 信号参数错误数
- 指向作为模板参数的数组的指针
- C++可变参数模板数组/访问元素
- 在 c++ 中没有参数的数组
- 具有双精度参数的数组
- 使用 C++11 的 begin() 和 end() 函数通过参数确定数组维度