C++ 解决方法:"从类型"B*"的表达式初始化类型"C*&"的引用无效"
c++ workaround: `invalid initialization of reference of type ‘C*&’ from expression of type ‘B*’
最近我第一次发现这个错误: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;
}
我知道出现错误是因为在编译方法时whatever
isB = true
它也在尝试编译alloc_c()
调用,因此它会检查该T = B
并且找不到任何alloc_c(B*& entry)
方法,因此失败了。另一种方式invalid initialization of reference of type ‘B*&’ from expression of type ‘C*’
当使用C
和isB = 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 进行测试。
相关文章:
- 尝试了解C++指针和数据类型初始化
- C++ 基元类型初始化与对象初始化
- C++ 2D shared_ptr数组使用抽象多态类型初始化
- 如何根据构造函数参数使用超类类型初始化成员变量?
- 使用没有默认构造函数的类/类型初始化自定义容器
- Visual C 新类型初始化
- 如何创建一个编译时静态类类型,该类型初始化具有特定值的成员容器
- 使用初始化列表的 POD 类型初始化不起作用
- 大括号之间的自定义类型初始化数组
- std::数组类型初始化
- 错误:类型初始化无效
- 基本类型初始化C++
- 使用派生类类型初始化模板类的静态数组
- 部分默认使用内部类型初始化模板模板参数
- 类型初始化使用 OpenSsl.net 异常
- 存储可以使用不同派生类型初始化的基类型成员变量时,请避免使用new
- 向量和基元类型初始化
- 基元类型初始化的构造函数语法和赋值语法之间的差异
- 是否可以从大括号类型初始化中推断出元组的模板参数
- 可从任何序列类型初始化的c++类