我们可以写一个 returns 函数指针指向函数模板的函数吗?
Can we write a function which returns a function pointer to a function template?
是否可以编写一个可以return指向模板函数或模板方法的函数或方法?
示例:
#include <iostream>
struct X1 {
static void Do(auto n) { std::cout << "1" << n << std::endl; }
// static auto GetPtr() { return X1::Do; } // how to write such a function?
};
struct X2 {
static void Do(int n) { std::cout << "2" << n << std::endl; }
//static auto GetPtr(){ return &Do; }
};
template <typename T> T magic(bool b, T t1, T t2) { return b ? t1 : t2; }
int main() {
auto l1 = magic(true, X1::Do, X2::Do);
// should be replaced by:
// auto l1 = magic( true, X1::GetPtr(), X2::GetPtr() );
l1(100);
}
如果我编译上面注释掉的函数,我从 gcc 得到:
main.cpp:1845:39: error: unable to deduce 'auto' from 'X1::Do'
背景:我目前正在尝试了解相同情况下的重载解决方案。在给定的情况下,您会看到 int
的重载被采用,因为一个函数指针 只有 有一个 int 参数,因此可以找到第二个指针重载。
我被那个问题触发了:
这里有人提出了一个答案,即 lambda 应该能够为函数指针提供转换运算符...但我没有看到它:-)
不,你不能 return 指向函数模板的指针,因为函数模板不是函数。这是一个模板。
// static auto GetPtr() { return X1::Do; } // how to write such a function?
您需要 &
来获取指向成员函数的指针,尽管 Do
不是成员函数,它是成员函数模板。您可以 return 指向 X1::Do<int>
或 X1::Do<double>
的指针,但没有指向 X1::Do
.
的指针
然而,您可以 return 具有重载调用运算符的仿函数,并且该运算符可以是模板:
struct foo {
template <typename T>
void operator()(const T& t) {}
void operator()(int x){}
};
foo magic() { return foo{}; }
int main() {
magic()(3); // calls operator()(int)
magic()("hello world"); // calls operator()<const char[12]>
}
在重读你的问题和你 link 的问答之后,我想你可能正在寻找这个:
#include <iostream>
struct X1 {
static void Do(auto n) { std::cout << "1" << n << std::endl; }
static auto GetPtr() { return &X1::Do<int>; }
};
struct X2 {
static void Do(int n) { std::cout << "2" << n << std::endl; }
static auto GetPtr(){ return &Do; }
};
template <typename T> T magic(bool b, T t1, T t2) { return b ? t1 : t2; }
int main() {
auto l1 = magic( true, X1::GetPtr(), X2::GetPtr() );
l1(100);
}
如上所述,您无法获取指向 X1::Do
的成员函数指针,但您可以获得指向 X1::Do<int>
.
的指针
正如您所指的将 lambda 转换为函数指针:此外,带有 auto
参数的 lambda 只能在选择参数类型后 转换为函数指针。考虑来自 cppreference 的示例:
void f1(int (*)(int)) {}
void f2(char (*)(int)) {}
void h(int (*)(int)) {} // #1
void h(char (*)(int)) {} // #2
auto glambda = [](auto a) { return a; };
f1(glambda); // OK
f2(glambda); // error: not convertible
h(glambda); // OK: calls #1 since #2 is not convertible
int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
无法获得指向类型 auto(auto)
的函数的指针(它不是函数的类型)。在上面的所有调用中,转换后不再有 auto
。相反,推导请求的类型并完成到相应函数指针的转换。
编译器不会提前“知道”您对 X1::GetPtr
的所有用途(通常)。您似乎希望编译器 1. 识别它是一个模板 2. 识别该函数的所有用途,并查看它是否可以“免费”推断出模板所需的所有实例化,可以这么说 - 在您的情况下只有在 magic
中使用,但这并不通用。
C++ 中没有这样的机制,编译器在解析函数时必须知道函数的类型,或者将其识别为模板(而不是猜测)。
简而言之,我认为您希望编译器做一些太难的事情,但它做不到。因此,您必须自己进行模板解析:
template<typename N>
static auto GetPtr() { return &X1::Do<N>; }
并用
调用它
magic(true, X1::GetPtr<int>(), X2::GetPtr());
是否可以编写一个可以return指向模板函数或模板方法的函数或方法?
示例:
#include <iostream>
struct X1 {
static void Do(auto n) { std::cout << "1" << n << std::endl; }
// static auto GetPtr() { return X1::Do; } // how to write such a function?
};
struct X2 {
static void Do(int n) { std::cout << "2" << n << std::endl; }
//static auto GetPtr(){ return &Do; }
};
template <typename T> T magic(bool b, T t1, T t2) { return b ? t1 : t2; }
int main() {
auto l1 = magic(true, X1::Do, X2::Do);
// should be replaced by:
// auto l1 = magic( true, X1::GetPtr(), X2::GetPtr() );
l1(100);
}
如果我编译上面注释掉的函数,我从 gcc 得到:
main.cpp:1845:39: error: unable to deduce 'auto' from 'X1::Do'
背景:我目前正在尝试了解相同情况下的重载解决方案。在给定的情况下,您会看到 int
的重载被采用,因为一个函数指针 只有 有一个 int 参数,因此可以找到第二个指针重载。
我被那个问题触发了:
这里有人提出了一个答案,即 lambda 应该能够为函数指针提供转换运算符...但我没有看到它:-)
不,你不能 return 指向函数模板的指针,因为函数模板不是函数。这是一个模板。
// static auto GetPtr() { return X1::Do; } // how to write such a function?
您需要 &
来获取指向成员函数的指针,尽管 Do
不是成员函数,它是成员函数模板。您可以 return 指向 X1::Do<int>
或 X1::Do<double>
的指针,但没有指向 X1::Do
.
然而,您可以 return 具有重载调用运算符的仿函数,并且该运算符可以是模板:
struct foo {
template <typename T>
void operator()(const T& t) {}
void operator()(int x){}
};
foo magic() { return foo{}; }
int main() {
magic()(3); // calls operator()(int)
magic()("hello world"); // calls operator()<const char[12]>
}
在重读你的问题和你 link 的问答之后,我想你可能正在寻找这个:
#include <iostream>
struct X1 {
static void Do(auto n) { std::cout << "1" << n << std::endl; }
static auto GetPtr() { return &X1::Do<int>; }
};
struct X2 {
static void Do(int n) { std::cout << "2" << n << std::endl; }
static auto GetPtr(){ return &Do; }
};
template <typename T> T magic(bool b, T t1, T t2) { return b ? t1 : t2; }
int main() {
auto l1 = magic( true, X1::GetPtr(), X2::GetPtr() );
l1(100);
}
如上所述,您无法获取指向 X1::Do
的成员函数指针,但您可以获得指向 X1::Do<int>
.
正如您所指的将 lambda 转换为函数指针:此外,带有 auto
参数的 lambda 只能在选择参数类型后 转换为函数指针。考虑来自 cppreference 的示例:
void f1(int (*)(int)) {} void f2(char (*)(int)) {} void h(int (*)(int)) {} // #1 void h(char (*)(int)) {} // #2 auto glambda = [](auto a) { return a; }; f1(glambda); // OK f2(glambda); // error: not convertible h(glambda); // OK: calls #1 since #2 is not convertible int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
无法获得指向类型 auto(auto)
的函数的指针(它不是函数的类型)。在上面的所有调用中,转换后不再有 auto
。相反,推导请求的类型并完成到相应函数指针的转换。
编译器不会提前“知道”您对 X1::GetPtr
的所有用途(通常)。您似乎希望编译器 1. 识别它是一个模板 2. 识别该函数的所有用途,并查看它是否可以“免费”推断出模板所需的所有实例化,可以这么说 - 在您的情况下只有在 magic
中使用,但这并不通用。
C++ 中没有这样的机制,编译器在解析函数时必须知道函数的类型,或者将其识别为模板(而不是猜测)。
简而言之,我认为您希望编译器做一些太难的事情,但它做不到。因此,您必须自己进行模板解析:
template<typename N>
static auto GetPtr() { return &X1::Do<N>; }
并用
调用它magic(true, X1::GetPtr<int>(), X2::GetPtr());