已关注 C++ Most efficient way to compare a variable to multiple values? ,我正在尝试构建一个以 initializer_list
作为参数的模板函数。当我仅使用字符串时就会出现问题。我有以下代码:
函数.hpp
template <typename T>
bool is_in(T const& val, initializer_list<T> const& liste)
{
for (const auto& i : liste)
if (val == i) return true;
return false;
};
main.cpp
#include "functions.hpp"
using namespace std;
int main()
{
string test("hello");
if (is_in(test, {"foo", "bar"}))
cout << "good" << endl;
else
cout << "bad" << endl;
return 0;
}
我收到以下错误:
main.cpp: In function ‘int main()’:
main.cpp:18:34: error: no matching function for call to ‘is_in(std::string&, <brace-enclosed initializer list>)’
main.cpp:18:34: note: candidate is:
In file included from personnage.hpp:11:0,
from main.cpp:1:
functions.hpp:16:6: note: template<class T> bool is_in(const T&, const std::initializer_list<_Tp>&)
functions.hpp:16:6: note: template argument deduction/substitution failed:
main.cpp:18:34: note: deduced conflicting types for parameter ‘_Tp’ (‘std::basic_string<char>’ and ‘const char*’)
我不明白的是:当我在 main
中使用 int
或 double
而不是 string
时code>,一切都很顺利...一个快速但肮脏的修复是将 is_in
声明为仅字符串函数,但它不是很令人满意。
有谁知道如何保持模板和使用字符串相同?
最佳答案
在您的函数模板中
template <typename T>
bool is_in(T const& val, initializer_list<T> const& liste)
两个参数都会参与template argument deduction ,并且从每个推导出的类型是不同的。 T
扣除为std::string
从第一个参数开始,如 char const *
从第二个开始(在模板参数推导过程中不考虑用户定义的转换,因此从 char const *
到 std::string
的隐式转换不会出现),这会导致编译错误。
有多种方法可以解决此问题。一种是构建 string
您传递给 is_in
的 braced-init-list 中的 s ,如果您可以使用 C++14 的 std::string_literals
,则可以非常简洁地完成此操作.
using namespace std::string_literals;
if (is_in(test, {"foo"s, "bar"s}))
// ^ ^
另一种方法是构造一个 initializer_list<string>
并将其传递给 is_in
if (is_in(test, initializer_list<string>{"foo", "bar"}))
您还可以重新定义is_in
这样两个参数类型的模板类型参数是不同的,毕竟你不关心它们是否相同,你只需要它们通过 operator==
进行比较即可
template <typename T, typename U>
bool is_in(T const& val, initializer_list<U> const& liste)
另一种选择是防止函数参数之一参与模板实参推导。
template<typename T>
struct identity
{ using type = T; };
template <typename T>
bool is_in(T const& val, initializer_list<typename identity<T>::type> const& liste)
以上T
第二个参数是non-deduced context ,因此只有第一个参数参与模板实参推导。
最后,is_in
可以替换为 std::any_of
.
auto elems = {"foo", "bar"};
if (any_of(begin(elems), end(elems), [&](string const& s) { return s == test; }))
如果您想避免使用 lambda 表达式样板,可以使用 boost::algorithm::any_of_equal
.
auto elems = {"foo", "bar"};
if (boost::algorithm::any_of_equal(elems, test))
关于c++ - 为什么带有initializer_list参数的模板对字符串的行为不正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33200019/