我相信这是因为您将 R 作为函数指针参数的返回类型。
注意这句话from a previous question
所以,当我们询问函数的签名时,我们必须给出两个答案:
对于是函数模板的特化的函数,
签名包括返回类型。
对于不是特化的函数,返回类型不是签名的一部分。
由于foo 只是一个重载函数,而void 不是foo 函数签名的一部分,R 将不帮助编译器推断出正确的函数重载。因此,使用foo 作为函数指针在main 范围内是不明确的。编译器通常通过匹配提供的参数的类型来解决重载,当函数指针本身时没有。
我相信这是最强大的解决方案,包括一个中间函数来解决以前不明确的函数指针。除了 int 之外,我还包括了一些其他类型,以展示将 auto 与下面提到的策略一起使用的灵活性。
#include <iostream>
#include <string>
void foo(int a){
std::cout << "int" << std::endl;
}
void foo(double a) {
std::cout << "double" << std::endl;
}
bool foo(char a) {
std::cout << "char" << std::endl;
return true;
}
template <typename T, typename R>
R print(const T& data, R(*fun)(typename T::type) ) {
return fun(data.value);
}
struct IntData{
using type = int;
type value;
};
struct DoubleData{
using type = double;
type value;
};
struct CharData{
using type = char;
type value;
};
template <typename T>
auto print2(const T& data)
{
auto(*fooResolved)(typename T::type) = foo;
return print(data,fooResolved);
}
int main()
{
IntData x{1};
print2(x);
DoubleData y{1.0};
print2(y);
CharData z{'a'};
bool result = false;
std::cout << "bool before: " << result << std::endl;
result = print2(z);
std::cout << "bool after : " << result << std::endl;
}
这里还有一些潜在的解决方案可以帮助说明问题:
(注意更改是删除 R 作为第二个模板参数)
#include <iostream>
#include <string>
void foo(int a){
std::cout << "int";
}
void foo(double a) {
std::cout << "double";
}
template <typename T>
void print(const T& data, void(*fun)(typename T::type) ) {
fun(data.value);
}
struct IntData{
using type = int;
type value;
};
int main()
{
IntData x{1};
print(x, foo);
}
还有这个(直接传值,允许多种返回类型)
#include <iostream>
#include <string>
void foo(int a){
std::cout << "int";
}
void foo(double a) {
std::cout << "double";
}
template <typename T, typename R>
void print(const T& data, R (*fun)(T) ) {
fun(data);
}
struct IntData{
using type = int;
type value;
};
int main()
{
IntData x{1};
print(x.value, foo);
}
并进一步说明原始问题(参见现在推导的返回类型)
#include <iostream>
#include <string>
void foo(int a){
std::cout << "int" << std::endl;
}
bool foo(double a) {
std::cout << "double" << std::endl;
return true;
}
template <typename T, typename R>
R print(const T& data, R (*fun)(T) ) {
return fun(data);
}
struct IntData{
using type = int;
type value;
};
struct DoubleData{
using type = double;
type value;
};
int main()
{
IntData x{1};
print(x.value, foo);
//foo(int) does not return a value
//bool test = print(x.value, foo); // Does not compile
DoubleData y{1.0};
bool result = false;
result = print(y.value, foo);
std::cout << result << std::endl;
}
当我们这样做的时候,你也可以通过明确指定你想要的 foo 来解决它们给定的原始代码
#include <iostream>
#include <string>
void foo(int a){
std::cout << "int";
}
void foo(double a) {
std::cout << "double";
}
template <typename T, typename R>
void print(const T& data, R(*fun)(typename T::type) ) {
fun(data.value);
}
struct IntData{
using type = int;
type value;
};
int main()
{
IntData x{1};
void(*fooResolved)(int) = foo;
print(x, fooResolved);
}