C :模板参数扣除传递模板作为参数函数到其他模板函数

C++: Template argument deduction when passing template functions as argument to other template functions

本文关键字:函数 参数 其他      更新时间:2023-10-16

我有以下示例代码的片段:

这个想法是有一个容器类,这里称为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成员函数)的代码以确保模板参数扣除em>工作?

(给定代码为c 11作为repl。它尚未支持C 14。C 14中的主要区别是可以省略transform的落后返回类型。但是,错误仍然相同。我对(仅)在C 14中起作用的解决方案感到满意。)

在您的示例中:

template <typename Function>
auto transform(Function fun) -> decltype(Box{fun(d_content)})

Box是类模板,而不是类。在课堂内,Box注入式class-name ,它始终是指Box<TContent>。因此,如果您需要更改 type (因为transform很可能需要这样做),这将行不通。您需要根据 Function是要指定 Box

template <class Function,
  class U = std::result_of_t<Function&(TContent)>>
Box<U> transform(Function fun)
{
  return Box<U>{fun(d_content)}; // or even better, Box<U>{std::invoke(fun, d_content)}
};

第二个问题是您调用它:

Box<std::tuple<int, int>> box3 = mybox.transform(&toTuple);

toTuple是函数模板,而不是函数。您无法将其传递给另一个功能模板,因为它没有类型,因此无法推导。和以前一样,您需要指定要您想要的 toTuple

Box<std::tuple<int, int>> box3 = mybox.transform(toTuple<int>);

或将整个内容包裹在lambda中(这是一个简化的实现,不关心副本,参考或sfinae):

Box<std::tuple<int, int>> box3 = mybox.transform([](auto x) { return toTuple(x); });