Bre*_*ier 40 c++ parameters templates variadic-functions c++11
我正在创建一个函数(可能是成员函数,而不是它很重要......也许它确实?)需要接受未知数量的参数,但我希望它们都是相同的类型.我知道我可以传入数组或向量,但我希望能够直接接受args列表而无需额外的结构甚至是额外的括号.看起来variadic函数本身并不是类型安全的,我不知道如何使用这个w/variadic模板函数.这基本上就是我的目标(更可能不是正确的代码,完全不是为了获取龙的列表,哈哈):
//typedef for dragon_list_t up here somewhere.
enum Maiden {
Eunice
, Beatrice
, Una_Brow
, Helga
, Aida
};
dragon_list_t make_dragon_list(Maiden...) {
//here be dragons
}
Run Code Online (Sandbox Code Playgroud)
要么
template<Maiden... Maidens> dragon_list_t make_dragon_list(Maidens...) {
//here be dragons
}
Run Code Online (Sandbox Code Playgroud)
用法
dragon_list_t dragons_to_slay
= make_dragon_list(Maiden.Eunice, Maiden.Helga, Maiden.Aida)
;
Run Code Online (Sandbox Code Playgroud)
尝试了类似于上面的一些事情,没有骰子.建议?我可能做出明显的疏忽?我知道这样做可能不是一件大事:
dragon_list_t make_dragon_list(std::array<Maiden> maidens) {
//here be dragons.
}
dragon_list_t dragons_to_slay
= make_dragon_list({Maiden.Eunice, Maiden.Helga, Maiden.Aida})
;
Run Code Online (Sandbox Code Playgroud)
但如果可能的话,我宁愿能够以第一种方式做到这一点.
Joh*_*itb 31
您可以通过可变参数模板接受参数,并让typechecking在转换后检查有效性.
您可以检查功能接口级别的可转换性,以利用重载决策来拒绝完全错误的参数,例如,使用SFINAE
template<typename R, typename...> struct fst { typedef R type; };
template<typename ...Args>
typename fst<void,
typename enable_if<
is_convertible<Args, ToType>::value
>::type...
>::type
f(Args...);
Run Code Online (Sandbox Code Playgroud)
对于你的用例,如果你知道从a std::array<>
到你的步骤,dragon_list_t
那么你已经解决了它,虽然根据上面的第一个选项("convert-later"):
template<typename ...Items>
dragon_list_t make_dragon_list(Items... maidens) {
std::array<Maiden, sizeof...(Items)> arr = {{ maidens ... }};
// here be dragons
}
Run Code Online (Sandbox Code Playgroud)
如果将此与上述is_convertible
方法结合使用,则会有一个拒绝早期模板,该模板也会对参数执行重载解析,如果不适用则拒绝它们.
Mot*_*tti 16
如果不使用template
不在包中的参数,则可变参数函数将解析为具有相同类型的所有参数.
以下max
是仅接受int
s(或可转换为int
)的扩展函数的示例.
int maximum(int n) // last argument must be an `int`
{
return n;
}
template<typename... Args>
int maximum(int n, Args... args) // first argument must be an int
{
return std::max(n, maximum(args...));
}
Run Code Online (Sandbox Code Playgroud)
说明:解压缩参数pack(args...
)时,编译器会查找最佳重载.如果包只有一个参数,那么唯一的候选者是maximum(int)
唯一的参数必须是和类型int
(或可转换为int
).如果包中有多个元素,则唯一的候选者是maximum(int, typename...)
第一个参数必须是类型int
(或可转换为int
).通过归纳证明包装中的所有类型必须是可转换的类型,这很简单int
.
Jer*_*fin 11
由于您已经包含了C++ 0x标记,因此显而易见的答案是查找初始化列表.初始化列表允许您指定ctor的多个参数,这些参数将自动转换为单个数据结构以供ctor处理.
它们的主要(独占?)用途恰好是你提到的那种情况,传递了许多相同类型的参数,用于创建某种列表/数组/其他对象集合.它将得到支持(例如)std::vector
,所以你可以使用类似的东西:
std::vector<dragon> dragons_to_slay{Eunice, Helga, Aida};
Run Code Online (Sandbox Code Playgroud)
创建三个dragon
对象的向量.大多数(全部?)其他系列都会包含相同的内容,所以如果你真的坚持一个龙列表,你也应该能够很容易地得到它.
Cof*_*ode 10
尽管问题被标记为 C++11,但我认为 C++20 + 概念解决方案值得添加,因为 GCC 现在已经支持,其他人很快就会跟进。
首先定义一个简单的概念
class mytype{};
template<typename T>
concept MyType = std::is_same<T, mytype>::value;
Run Code Online (Sandbox Code Playgroud)
然后只需使用可变模板参数
template<MyType ... Args>
void func(Args &&... args){
// do something here
}
Run Code Online (Sandbox Code Playgroud)
随着概念的出现变得更加容易!
Jan*_*šek 10
最近的一个提议,同构可变参数函数,通过使类似你的第一个构造合法的东西来解决这个问题。除了当然要使用参数包,您还必须对其进行命名。此外,确切的语法似乎还不是很具体。
因此,根据提案,这实际上是合法的(您可以在论文的“模板介绍人”段落中看到类似的结构):
dragon_list_t make_dragon_list(Maiden... maidens) {
//here be dragons
}
Run Code Online (Sandbox Code Playgroud)
我最近需要将参数包限制为仅一种类型,或者至少可以转换为该类型。我最终找到了另一种方法:
#include <type_traits>
#include <string>
template <template<typename> class Trait, typename Head, typename ...Tail>
struct check_all {
enum { value = Trait<Head>::value && check_all<Trait, Tail...>::value };
};
template <template<typename> class Trait, typename Head>
struct check_all<Trait, Head> {
enum { value = Trait<Head>::value };
};
template <typename ...Args>
struct foo {
// Using C++11 template alias as compile time std::bind
template <typename T>
using Requirement = std::is_convertible<double, T>;
static_assert(check_all<Requirement, Args...>::value, "Must convert to double");
};
int main() {
foo<int, char, float, double>();
foo<int, std::string>(); // Errors, no conversion
}
Run Code Online (Sandbox Code Playgroud)
我喜欢此解决方案的地方是,我也可以将其应用于check_all
其他特征。
使用c++17,你可以写
template <class T, class... Ts, class = std::enable_if_t<(std::is_same_v<T, Ts> && ...)>
void fun(T x, Ts... xs)
{
}
Run Code Online (Sandbox Code Playgroud)