我们可以写一个 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());