模板推导:为什么函数指针模板定义在 const and/or 引用时不匹配?

template deduction: Why the function pointer templates definitions are not matching when they are const and/or references?

在问题 之后,我正在尝试编写一种 C++ 98 兼容的方式来打印任何函数指针。

为此,我使用了一个伪造的 C++ "variadic" 模板,即编写最多 n 个参数的所有函数定义。然而,我的伪可变参数仅适用于参数为 0 的函数指针,如下例所示:https://godbolt.org/z/x4TVHS

#include<iostream>

template<typename Return>
std::ostream& operator <<(std::ostream& os, Return(*pointer)() ) {
    return os << (void*) pointer;
}

template<typename Return, typename T0>
std::ostream& operator <<(std::ostream& os, Return(*pointer)( const T0& t0 ) ) {
    return os << (void*) pointer;
}

template<typename Return, typename T0, typename T1>
std::ostream& operator <<(std::ostream& os, Return(*pointer)( const T0& t0, const T1& t1 ) ) {
    return os << (void*) pointer;
}

void fun_void_void(){};
void fun_void_double(double d){};
double fun_double_double(double d){return d;}

int main() {
    std::cout << "1. " << fun_void_void << std::endl;
    std::cout << "2. " << fun_void_double << std::endl;
    std::cout << "3. " << fun_double_double << std::endl;
}

// Prints:
//    1. funptr 0x100401080
//    2. funptr 1
//    3. funptr 1

如果我使用 C++11 真正的可变参数模板编写等效版本,那么一切正常:https://godbolt.org/z/s6wdgp

#include<iostream>

template<typename Return, typename... Args>
std::ostream& operator <<(std::ostream& os, Return(*pointer)( Args... ) ) {
    return os << (void*) pointer;
}

void fun_void_void(){};
void fun_void_double(double d){};
double fun_double_double(double d){return d;}

int main() {
    std::cout << "1. " << fun_void_void << std::endl;
    std::cout << "2. " << fun_void_double << std::endl;
    std::cout << "3. " << fun_double_double << std::endl;
}

// Prints:
//    1. funptr 0x100401080
//    2. funptr 0x100401087
//    3. funptr 0x100401093

分析代码后,我注意到 then 之间的唯一区别是 C++11 示例中的类型不是 const 引用。然后,我从 C++98 中删除了常量和引用,它开始工作了:https://godbolt.org/z/ZrF66b

#include<iostream>

template<typename Return>
std::ostream& operator <<(std::ostream& os, Return(*pointer)() ) {
    return os << (void*) pointer;
}

template<typename Return, typename T0>
std::ostream& operator <<(std::ostream& os, Return(*pointer)( T0 ) ) {
    return os << (void*) pointer;
}

template<typename Return, typename T0, typename T1>
std::ostream& operator <<(std::ostream& os, Return(*pointer)( T0, T1 ) ) {
    return os << (void*) pointer;
}

void fun_void_void(){};
void fun_void_double(double d){};
double fun_double_double(double d){return d;}

int main() {
    std::cout << "1. " << fun_void_void << std::endl;
    std::cout << "2. " << fun_void_double << std::endl;
    std::cout << "3. " << fun_double_double << std::endl;
}

// Prints:
//    1. funptr 0x100401080
//    2. funptr 0x100401087
//    3. funptr 0x100401093

为什么函数指针模板定义在 const and/or 引用时不匹配?

template<typename Return, typename T0>
std::ostream& operator <<(std::ostream& os, Return(*pointer)( const T0& t0 ) ) {
  return os << (void*) pointer;
}
void f(int) {}
os << f;

这不起作用,因为没有类型 ReturnT0 使得 Return(*)(const T&) 匹配 void(*)(int) 完全 .

顺便说一句,覆盖不在关联命名空间中的运算符是不好的,因为它非常脆弱。并且您不能覆盖 std 中的运算符。所以这个计划很糟糕。