考虑功能:
template<typename T>
void printme(T&& t) {
for (auto i : t)
std::cout << i;
}
或任何其他需要一个参数具有 begin()/end() 启用类型的函数。
为什么以下行为是非法的?
printme({'a', 'b', 'c'});
当所有这些都是合法的时:
printme(std::vector<char>({'a', 'b', 'c'}));
printme(std::string("abc"));
printme(std::array<char, 3> {'a', 'b', 'c'});
我们甚至可以这样写:
const auto il = {'a', 'b', 'c'};
printme(il);
或
printme<std::initializer_list<char>>({'a', 'b', 'c'});
您的第一行
printme({'a', 'b', 'c'})
是非法的,因为无法推断模板参数T
。如果您明确指定模板参数它将起作用,例如printme<vector<char>>({'a', 'b', 'c'})
或 printme<initializer_list<char>>({'a', 'b', 'c'})
。
您列出的其他参数是合法的,因为参数具有明确定义的类型,因此可以很好地推导模板参数
T
。
带有
auto
的代码片段也有效,因为 il
被认为是 std::initializer_list<char>
类型,因此可以推导出 printme()
的模板参数。
这里唯一“有趣”的部分是
auto
将选择类型 std::initializer_list<char>
但模板参数不会。这是因为 C++11 标准的第 14.8.2.5/5 节明确指出这是模板参数的非推导上下文:
关联参数是初始化列表(8.5.4)但参数没有 std::initializer_list 或对可能 cv 限定的 std::initializer_list 类型的引用的函数参数。 [示例:
template<class T> void g(T); g({1,2,3}); // error: no argument deduced for T
—结束示例]
但是,对于
auto
,§ 7.1.6.4/6 明确支持 std::initializer_list<>
如果初始化器是 braced-init-list (8.5.4),带有
。std::initializer_list<U>
您还可以重载该函数以显式采用initializer_list类型的参数。
template<typename T>
void printme(std::initializer_list<T> t) {
for (auto i : t)
std::cout << i;
}
这在第 § 14.8.2.5/5 条中有明确规定
关联参数是一个函数参数 初始化列表但参数没有
或参考可能符合简历要求的内容std::initializer_list
类型。 [ 示例:std::initializer_list
template<class T> void g(T); g({1,2,3}); // error: no argument deduced for T
—示例结束]
要使其正常工作,您可以显式指定模板参数类型。
printme<std::initializer_list<int>>( {1,2,3,4} );
我找到了一个解决方案,该解决方案不适用于问题中提供的
printme
功能,但适用于类似的功能:
这就是我开始的地方:
template <typename V, typename C>
bool in(const C& container, const V& element)
{
return std::find(container.begin(), container.end(), element) != container.end();
}
无法编译,例如:
in({1, 2, 3}, 1);
与
Candidate template ignored: couldn't infer template argument 'C'
基于此处的另一个答案,我们可以为
std::initializer_list
添加模板专业化:
template <typename V, typename C>
bool in(const C& container, const V& element)
{
return std::find(container.begin(), container.end(), element) != container.end();
}
template <typename V>
bool in(const std::initializer_list<V>& container, const V& element)
{
return std::find(container.begin(), container.end(), element) != container.end();
}
这看起来很傻。
但以下方法也有效:
template <typename V, typename C = std::initializer_list<V>>
bool in(const C& container, const V& element)
{
return std::find(container.begin(), container.end(), element) != container.end();
}