我有以下示例代码片段:
这个想法是有一个容器类,这里称为Box
,我们可能希望通过将函数映射到其当前内容来创建该容器的新版本。
#include <iostream>
#include <tuple>
template <typename TContent>
class Box
{
TContent d_content;
public:
Box(TContent content)
:
d_content(content)
{}
TContent content() const
{
return d_content;
}
template <typename Function>
auto transform(Function fun) -> decltype(Box{fun(d_content)})
{
return Box{fun(d_content)};
};
};
template <typename TElem>
std::tuple<TElem, TElem> toTuple(TElem thing)
{
std::cout << "Transforming " << thing << "to tuple.\n";
return std::make_tuple(thing, thing);
}
int main() {
std::cout << "Hello World!\n";
Box<int> mybox{10};
Box<int> box2 = mybox.transform([](int content){ return content * 2;});
std::cout << "Transformed box: " << box2.content() << '\n';
Box<std::tuple<int, int>> box3 = mybox.transform(&toTuple); // <- Template argument deduction/substitution fails here!
std::cout << "Transformed box: " << std::get<0>(box3.content()) << '\n';
}
在创建 box3 的第 42 行,模板参数推导/替换失败:
main.cpp: In function 'int main()':
main.cpp:42:60: error: no matching function for call to 'Box<int>::transform(<unresolved overloaded function type>)'
Box<std::tuple<int, int>> box3 = mybox.transform(&toTuple);
^
main.cpp:22:8: note: candidate: template<class Function> decltype (Box<TContent>{fun(((Box<TContent>*)this)->Box<TContent>::d_content)}) Box<TContent>::transform(Function) [with Function = Function; TContent = int]
auto transform(Function fun) -> decltype(Box{fun(d_content)})
^~~~~~~~~
main.cpp:22:8: note: template argument deduction/substitution failed:
main.cpp:42:60: note: couldn't deduce template parameter 'Function'
Box<std::tuple<int, int>> box3 = mybox.transform(&toTuple);
^
exit status 1
尝试将模板函数(函数模板?)传递给本身需要模板参数参数的函数时,似乎就是这种情况。
到目前为止,我发现避免这种情况的唯一方法是将所有模板函数包装在 lambdas 或其他非模板函数中。这当然不是最理想的,因为它引入了很多样板。
为什么在这种情况下模板参数推导失败,有没有办法改变Box
类(和/或其transform
成员函数)的代码以确保模板参数推导有效?
(给定的代码是 C++11,因为 repl.it 还不支持 c++14。C++14 的主要区别是transform
可以省略尾随返回类型。但是,错误仍然相同. 我对(仅)也适用于 C++14 的解决方案感到满意。)