Mar*_*ica 16 c++ templates variadic-templates c++11 c++17
我想编写一个接受可变数量的字符串文字的函数.如果我用C语写作,我必须写一些类似于:
void foo(const char *first, ...);
Run Code Online (Sandbox Code Playgroud)
然后调用看起来像:
foo( "hello", "world", (const char*)NULL );
Run Code Online (Sandbox Code Playgroud)
感觉它应该可以在C++中做得更好.我想出的最好的是:
template <typename... Args>
void foo(const char* first, Args... args) {
foo(first);
foo(args);
}
void foo(const char* first) { /* Do actual work */ }
Run Code Online (Sandbox Code Playgroud)
被称为:
foo("hello", "world");
Run Code Online (Sandbox Code Playgroud)
但是我担心递归本质,以及我们在得到单个参数之前不进行任何类型检查的事实,如果有人调用,会使错误混乱foo("bad", "argument", "next", 42).我想要写的,是这样的:
void foo(const char* args...) {
for (const char* arg : args) {
// Real work
}
}
Run Code Online (Sandbox Code Playgroud)
有什么建议?
编辑:还有选项void fn(std::initializer_list<const char *> args),但这使得foo({"hello", "world"});我想避免的呼叫.
lll*_*lll 15
我想你可能想要这样的东西:
template<class... Args,
std::enable_if_t<(std::is_same_v<const char*, Args> && ...), int> = 0>
void foo(Args... args ){
for (const char* arg : {args...}) {
std::cout << arg << "\n";
}
}
int main() {
foo("hello", "world");
}
Run Code Online (Sandbox Code Playgroud)
注意:不能仅匹配字符串文字.你最接近的是匹配一个const char数组.
要进行类型检查,请使用带有const char数组的函数模板.
要使用基于范围的循环遍历它们for,我们需要将其转换为initializer_list<const char*>.我们可以在基于范围的for语句中直接使用大括号,因为数组会衰减到指针.
以下是函数模板的外观(注意:这适用于零个或多个字符串文字.如果需要一个或多个,请更改函数签名以至少使用一个参数.):
template<size_t N>
using cstring_literal_type = const char (&)[N];
template<size_t... Ns>
void foo(cstring_literal_type<Ns>... args)
{
for (const char* arg : {args...})
{
// Real work
}
}
Run Code Online (Sandbox Code Playgroud)
虽然所有其他答案都可以解决问题,但您还可以执行以下操作:
\n\nnamespace detail\n{\n void foo(std::initializer_list<const char*> strings);\n}\n\ntemplate<typename... Types>\nvoid foo(const Types... strings)\n{\n detail::foo({strings...});\n}\nRun Code Online (Sandbox Code Playgroud)\n\n这种方法似乎(至少对我来说)比使用 SFINAE 更具可读性并且适用于 C++11。此外,它允许您将实现移动foo到cpp文件中,这也可能很有用。
编辑:至少在 GCC 8.1 中,当使用非const char*参数调用时,我的方法似乎会产生更好的错误消息:
foo("a", "b", 42, "c");\nRun Code Online (Sandbox Code Playgroud)\n\n该实现编译为:
\n\ntest.cpp: In instantiation of \xe2\x80\x98void foo_1(const ArgTypes ...) [with ArgTypes = {const char*, int, const char*, const char*}]\xe2\x80\x99:\ntest.cpp:17:29: required from here\ntest.cpp:12:16: error: invalid conversion from \xe2\x80\x98int\xe2\x80\x99 to \xe2\x80\x98const char*\xe2\x80\x99 [-fpermissive]\n detail::foo({strings...});\n ~~~~~~~~~~~^~~~~~~~~~~~~~\nRun Code Online (Sandbox Code Playgroud)\n\n而基于 SFINAE(liliscent 的实现)会产生:
\n\ntest2.cpp: In function \xe2\x80\x98int main()\xe2\x80\x99:\ntest2.cpp:14:29: error: no matching function for call to \xe2\x80\x98foo(const char [6], const char [6], int)\xe2\x80\x99\n foo("hello", "world", 42);\n ^\ntest2.cpp:7:6: note: candidate: \xe2\x80\x98template<class ... Args, typename std::enable_if<(is_same_v<const char*, Args> && ...), int>::type <anonymous> > void foo(Args ...)\xe2\x80\x99\n void foo(Args... args ){\n ^~~\ntest2.cpp:7:6: note: template argument deduction/substitution failed:\ntest2.cpp:6:73: error: no type named \xe2\x80\x98type\xe2\x80\x99 in \xe2\x80\x98struct std::enable_if<false, int>\xe2\x80\x99\n std::enable_if_t<(std::is_same_v<const char*, Args> && ...), int> = 0>\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
1172 次 |
| 最近记录: |