我想要编写一个函数,它接受一个可变数目的字符串文本。如果我是用C写的话,我就得写这样的东西:
void foo(const char *first, ...);然后电话就会看起来像:
foo( "hello", "world", (const char*)NULL );感觉应该有可能在C++上做得更好。我想出的最好办法是:
template <typename... Args>
void foo(const char* first, Args... args) {
foo(first);
foo(args);
}
void foo(const char* first) { /* Do actual work */ }称为:
foo("hello", "world");但是,我担心递归的性质,以及在到达单个参数之前不进行任何类型检查的事实,如果有人调用foo("bad", "argument", "next", 42),就会造成错误混淆。我想写的是:
void foo(const char* args...) {
for (const char* arg : args) {
// Real work
}
}有什么建议吗?
编辑:还有void fn(std::initializer_list<const char *> args)的选项,但这使得调用成为foo({"hello", "world"});,这是我想要避免的。
发布于 2018-05-15 20:15:14
虽然所有其他答案都解决了这个问题,但您还可以执行以下操作:
namespace detail
{
void foo(std::initializer_list<const char*> strings);
}
template<typename... Types>
void foo(const Types... strings)
{
detail::foo({strings...});
}这种方法(至少对我来说)比使用SFINAE和使用C++11更易读,而且,它允许您将foo的实现移动到cpp文件中,这可能也很有用。
编辑:至少在GCC 8.1中,当使用非const char*参数调用时,我的方法似乎产生了更好的错误信息:
foo("a", "b", 42, "c");这一实现的编译方式如下:
test.cpp: In instantiation of ‘void foo_1(const ArgTypes ...) [with ArgTypes = {const char*, int, const char*, const char*}]’:
test.cpp:17:29: required from here
test.cpp:12:16: error: invalid conversion from ‘int’ to ‘const char*’ [-fpermissive]
detail::foo({strings...});
~~~~~~~~~~~^~~~~~~~~~~~~~而SFINAE(丁香的实施)则产生:
test2.cpp: In function ‘int main()’:
test2.cpp:14:29: error: no matching function for call to ‘foo(const char [6], const char [6], int)’
foo("hello", "world", 42);
^
test2.cpp:7:6: note: candidate: ‘template<class ... Args, typename std::enable_if<(is_same_v<const char*, Args> && ...), int>::type <anonymous> > void foo(Args ...)’
void foo(Args... args ){
^~~
test2.cpp:7:6: note: template argument deduction/substitution failed:
test2.cpp:6:73: error: no type named ‘type’ in ‘struct std::enable_if<false, int>’
std::enable_if_t<(std::is_same_v<const char*, Args> && ...), int> = 0>发布于 2018-05-15 15:11:57
我想你可能想要这样的东西:
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");
}发布于 2018-05-15 17:18:00
注意:不可能只匹配字符串文本。最接近的是匹配一个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
}
}https://stackoverflow.com/questions/50353535
复制相似问题