两个不完全相同的函数指针曾经兼容吗?

时间:2018-12-24 12:38:58

标签: c++ function-pointers undefined-behavior

我有以下函数指针类型:

typedef int(*a)(char*);
typedef const int(*b)(char*);
typedef int(*c)(char* const);
typedef int(*d)(const char*);
typedef long(*e)(char*);
typedef int(*f)(unsigned char*);
typedef void(*g)(char*);

我知道ac完全相同(至少在C ++中是一样),因为在函数原型参数类型中忽略了const

我的问题是,如果我有一个a类型的变量,以及这7种类型中的任何一个变量,我可以将其中哪一个分配给第一个变量?

a foo = NULL;
(a/b/c/d/e/f/g) bar = ...;
foo = bar;  // Is this UB based on the type of bar?

我能检测到吗?

我尝试利用template<class F> ::std::function::operator=(F&&)的定义方式,因为“除非参数类型为Args的f可调用...并且返回类型R,否则该运算符不会参与重载解析。”

#include <iostream>
#include <functional>
#include <type_traits>

template<class T, class U>
static void _print_is_assignable(const char* const t_name, const char* const u_name) {
    using function_t = ::std::function<typename ::std::remove_pointer<T>::type>;
    std::cout << t_name;
    std::cout << (::std::is_assignable<function_t&, U>::value ? " == " : " != ");
    std::cout << u_name << '\n';
}

#define PRINT_IS_ASSIGNABLE(T, U) _print_is_assignable<T, U>(#T, #U)

typedef int(*a)(char*);
typedef const int(*b)(char*);
typedef int(*c)(char* const);
typedef int(*d)(const char*);
typedef long(*e)(char*);
typedef int(*f)(unsigned char*);
typedef void(*g)(char*);

int main() {
    PRINT_IS_ASSIGNABLE(a, a);  // a == a
    PRINT_IS_ASSIGNABLE(a, b);  // a == b
    PRINT_IS_ASSIGNABLE(a, c);  // a == c
    PRINT_IS_ASSIGNABLE(a, d);  // a == d
    PRINT_IS_ASSIGNABLE(a, e);  // a == e
    PRINT_IS_ASSIGNABLE(a, f);  // a != f
    PRINT_IS_ASSIGNABLE(a, g);  // a != g
    PRINT_IS_ASSIGNABLE(g, a);  // g == a
}

1 个答案:

答案 0 :(得分:3)

我已经阅读了一些规范,而我能找到的最接近的内容是在5.2.10 [expr.reinterpret.cast]节中:

  

可以将功能指针显式转换为其他类型的功能指针。通过指向与函数定义中使用的类型不同的函数类型的指针(8.3.5)调用函数的效果是不确定的。除了将类型“将指针指向T1”的prvalue转换为“指针指向T2”(其​​中T1和T2是函数类型)并返回其原始类型会产生原始指针值外,这种指针转换的结果未指定

这似乎告诉我,不,这是未定义的行为,除非函数指针类型完全相同,并且我必须回退到原始类型。

经过一些测试,g ++似乎并不介意返回的指针是什么,返回的指针是什么,以及返回类型是否为const限定都没有关系,这很有意义。尝试处理几乎兼容的类型时,我只需要使用std::function