模板推导:为什么函数指针模板定义在 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;
这不起作用,因为没有类型 Return
和 T0
使得 Return(*)(const T&)
匹配 void(*)(int)
完全 .
顺便说一句,覆盖不在关联命名空间中的运算符是不好的,因为它非常脆弱。并且您不能覆盖 std
中的运算符。所以这个计划很糟糕。
在问题
为此,我使用了一个伪造的 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;
这不起作用,因为没有类型 Return
和 T0
使得 Return(*)(const T&)
匹配 void(*)(int)
完全 .
顺便说一句,覆盖不在关联命名空间中的运算符是不好的,因为它非常脆弱。并且您不能覆盖 std
中的运算符。所以这个计划很糟糕。