C++ 解决方法:"从类型"B*"的表达式初始化类型"C*&"的引用无效"

c++ workaround: `invalid initialization of reference of type ‘C*&’ from expression of type ‘B*’

本文关键字:类型 初始化 引用 表达式 无效 解决 方法 C++      更新时间:2023-10-16

最近我第一次发现这个错误:invalid initialization of reference of type ‘C*&’ from expression of type ‘B*’.将代码从gcc 4.9移植到gcc 6时出现错误。下面我粘贴了一个最小的代码示例。

class A {
public:
A() : a(1) {};
virtual ~A() {};
int a;
};
class B : public A {
public:
B() : val(2) {};
int val;
};
class C : public A {
public:
C() : val(3) {};
float val;
};
int alloc_b(B*& entry) {
try {
entry = new B;
} catch(...) {
return -1;
}
return 0;
}
int alloc_c(C*& entry) {
try {
entry = new C;
} catch(...) {
return -1;
}
return 0;
}
template<typename T>
int whatever(const bool isB) {
T* entry = NULL;
if(isB) {
alloc_b(entry);
} else {
alloc_c(entry);
}
std::cout << entry->val << "n";
}
int main() {
int rv;
B* ptrB;
C* ptrC;
whatever<B>(true);
whatever<C>(false);
return 0;
}

我知道出现错误是因为在编译方法时whateverisB = true它也在尝试编译alloc_c()调用,因此它会检查该T = B并且找不到任何alloc_c(B*& entry)方法,因此失败了。另一种方式invalid initialization of reference of type ‘B*&’ from expression of type ‘C*’当使用CisB = false类型调用方法whatever时。

我只是想知道解决这个问题的最干净方法是什么。我找到的唯一解决方案是创建一个具有一些专门性的方法模板alloc

template<typename T>
int alloc(T*& entry) {
static_assert((std::is_same<decltype(entry), B>::value ||
std::is_same<decltype(entry), C>::value),
"Class must be A or B");
}
template<>
int alloc(B*& entry) {
return alloc_b(entry);
}
template<>
int alloc(C*& entry) {
return alloc_c(entry);
}

然后从whatever函数内部,我会调用该分配而不是其他分配。

template<typename T>
int whatever(const bool isB) {
T* entry = NULL;
alloc(entry);
std::cout << entry->val << "n";
}

但我相信必须有一种更干净的方法来解决这个错误。

我知道

出现错误是因为当编译带有isB = true的方法时,它也在尝试编译alloc_c((调用,因此它检查T = B并且找不到任何alloc_c(B*&entry(方法,因此失败。

您可以通过改为提供此编译时评估isB来防止这种情况发生:

template<typename T, bool isB>
int whatever();

现在,使用if constexpr将为您提供所需的功能,而不会对您的代码造成太大伤害:

template<typename T, bool isB>
int whatever() {
T* entry = NULL;
if constexpr (isB) {
alloc_b(entry);
} else {
alloc_c(entry);
}
std::cout << entry->val << "n";
}
whatever<B, true>();
whatever<C, false>();

现场演示

编辑

如果没有if constexpr,SFINAE 仍然有效 - 你只需要做更多的输入:

template<typename T, bool isB>
typename std::enable_if<isB, int>::type whatever() {
T* entry = NULL;
alloc_b(entry);
std::cout << entry->val << "n";
}
template<typename T, bool isB>
typename std::enable_if<!isB, int>::type whatever() {
T* entry = NULL;
alloc_c(entry);
std::cout << entry->val << "n";
}

使用 gcc 6.1.0 进行测试。