模板推论:为什么函数指针模板定义为const和/或引用时不匹配?

问题描述 投票:0回答:1

问题Is possible to fix the iostream cout/cerr member function pointers being printed as 1 or true?之后,我试图编写一种与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

分析代码后,我注意到这之间的唯一区别是C ++ 11示例中的类型不是const引用。然后,我从C ++ 98中删除了constness和引用,它开始起作用: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和/或引用时不匹配?

c++ c++11 pointers templates c++98
1个回答
0
投票

对于单个参数,您具有此模板:

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

它接受类型的函数

Return()(const T0& t0);

您对其进行测试的功能是

void fun_void_double(double d){};

没有T0使模板与该函数的类型匹配。

通常,为您不拥有的类型编写包罗万象的运算符不是最佳策略。如果您想轻松地传递函数指针,则可以使用例如标签:

#include <iostream>

template <typename T>
struct as_void_impl { 
    T* value; 
    friend std::ostream& operator<<(std::ostream& out, const as_void_impl& x) {
        return out << x.value;
    }
};
template <typename T>
as_void_impl<T> as_void(T* t) { return {t}; }

void fun_void_double(double d){};

int main() {
    std::cout << as_void(fun_void_double);
}

这具有为任何东西,但只有您明确要求的东西工作的指针的好处。

© www.soinside.com 2019 - 2024. All rights reserved.