c++ - 在模板函数中推导模板函数(使用C++概念)

标签 c++ templates c++-concepts

此代码导致错误error: no matching function to call to 'put'

#include <concepts>
#include <type_traits>  // for is_invocable_r_v
#include <iostream>

template <typename T>
T add(T a, T b)
{
    return a + b;
}

template <typename T, typename F>
    requires std::is_invocable_r_v<T, F, T, T>
void put(T& r, T a, T b, F f)
{
    r = f(a, b);
}

int main()
{
    int x;
    put(x, 1, 2, add);
    std::cout << "x = " << x << '\n';
}
这似乎是因为概念虽然可以约束模板参数,但无助于推导模板参数。
我可以使用函数指针定义put,而不必引入参数F。但是,它将排除更通用的函数对象,例如(捕获)用于f的lambda。
template <typename T>
void put(T& r, T a, T b, T (f)(T, T))
{
    r = f(a, b);
}
当然,我可以更具体一点,put(x, 1, 2, add<int>),它将适用于这个简单的示例。但是,在更一般的情况下(例如编写库),我希望编译器为我做这件事,并从外部上下文确定add的正确实例。
是否可以让编译器知道F是某种函数类型并使其推断出来?

最佳答案

通过额外的重载,您可以使编译器解析add,并且仍然支持函数对象。

template <typename T>
T add(T a, T b)
{
    return a + b;
}

template <typename T, typename F>
    requires std::is_invocable_r_v<T, F, T, T>
void put(T& r, T a, T b, F f)
{
    r = f(a, b);
}


template <typename T>
void put(T& r, T a, T b, T(f)(T,T))
{
    r = f(a, b);
}

auto template_lambda_add = []<class T>(T a, T b) -> T { return a + b; };

int main()
{
    int x;
    put(x, 1, 2, add);
    std::cout << "x = " << x << '\n';
    put(x, 1, 2, std::plus<void>{});
    std::cout << "x = " << x << '\n';
    put(x, 1, 2, [](auto a, auto b){return a+b;});
    std::cout << "x = " << x << '\n';
    put(x, 1, 2, template_lambda_add);
    std::cout << "x = " << x << '\n';
}
编辑:
还支持模板lambda。香港专业教育学院增加了一个例子来演示。
作为补充说明,模板lambda的语法如下
auto lambda_add = []<class T>(T a, T b) -> T { return a + b; };
类似于以下内容的是模板变量声明。即用于创建lambda(而不是受试的lambda)的模板。
template <class T>
auto lambda_add = [](T a, T b) -> T { return a + b; };
edit2:更多的东西

Can I also make a templated function object work?


是的多数民众赞成在什么 std::plus<void> 基本上是。
您必须通过模板操作符,而不是结构。例如
struct Add {
template <class T>
T operator()(T a, T b) { return a + b; } 
};
也关于为什么重载template <typename T> void put(T& r, T a, T b, T(f)(T,T)) { r = f(a, b); },起作用的原因
基本上,编译器已经从前三个参数知道了T是什么,因此它可以使用它来找出如何实例化add。为了更明确地说明我们希望从前三个参数而非函数ptr参数推导出T的事实,我们可以像这样使用 std::type_identity
template <typename T>
void put(T& r, T a, T b, std::type_identity_t<T(T,T)> f)
{
    r = f(a, b);
}

关于c++ - 在模板函数中推导模板函数(使用C++概念),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62647589/

相关文章:

c++ - Windows-7/64 位上的免注册 COM 对象

c++ - 为什么不能将函数指针与没有显式 & 函数名称的模板函数进行比较?

templates - 一些D模板问题

c++ - 什么概念允许容器在基于范围的 for 循环中可用?

c++ - ->* 运算符应该在何时何地重载?

c++ - 错误 C2504 : 'ios' : base class undefined

c++ - 奇怪的模板命名空间问题

c++ - 部分特化类的成员定义

c++ - 除了概念之外,在类型约束中禁止类型特征的理由是什么?

包含线程函数的对象 vector 上的 C++ 错误