MSVC:模板化转换运算符和多重继承的错误
MSVC: Bug with templated conversion operators and multiple inheritance
我有以下代码不能用 MSVC 编译。它与 gcc、clang 和 icc 编译良好。我想这是一个错误,对吧?
你have/know有解决办法吗?
#include <type_traits>
struct A
{
template <
typename C
,typename = std::enable_if_t<std::is_same_v<C, int>>
>
operator C() const{
return 12;
}
};
struct B
{
template <
typename C
, typename = std::enable_if_t<std::is_same_v<C, char>>
, typename F = int
>
operator C() const
{
return 'A';
}
};
struct AB : A, B
{
};
int main(){
AB ab;
int i = ab;
char c = ab;
}
错误文本是:
example.cpp
<source>(34): error C2440: 'initializing': cannot convert from 'AB' to 'char'
<source>(34): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
Compiler returned: 2
我已经向 Microsoft 发布了 bug report。
在 godbolt
上查看
这似乎确实是 MSVC 中的错误。在运算符模板推导过程中似乎没有考虑最后一个基数。例如
struct AB : A, B // -> only A's templated operator considered
struct AB : B, A // -> only B's templated operator considered
在您的情况下,您可以删除模板化运算符并直接使用类型 (Live)(在这种情况下使用模板无论如何都没有多大意义):
#include <type_traits>
struct A
{
operator int() const{ return 12;}
};
struct B
{
operator char() const { return 'A'; }
};
struct AB : A, B
{
};
int main(){
AB ab;
int i = ab;
char c = ab;
}
或者您可以改用 class 模板,例如 (Live):
#include <type_traits>
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
struct A
{
operator T() const{
return 12;
}
};
template <typename T, typename = std::enable_if_t<std::is_same_v<T,char>>>
struct B
{
operator T() const
{
return 'A';
}
};
struct AB : A<int>, B<char>
{
};
int main(){
AB ab;
int i = ab;
char c = ab;
}
或者您可以在单个 class (Live):
中重载模板化运算符
struct A
{
template <
typename C
, typename = std::enable_if_t<std::is_same_v<C, int>>
>
operator C() const {
return 12;
}
template <
typename C
, typename = std::enable_if_t<std::is_same_v<C, char>>
, typename F = int
>
operator C() const
{
return 'A';
}
};
struct AB : A
{
};
int main() {
AB ab;
int i = ab;
char c = ab;
}
我找到了 workaround.
在这里你可以看到我的解决方案。我更改了继承层次结构并引入了转发转换运算符:
#include <type_traits>
#include <utility>
struct A
{
template <
typename C
,typename = std::enable_if_t<std::is_same_v<C, int>>
>
operator C() const{
return 12;
}
};
struct B : A
{
template <
typename C
, typename = std::enable_if_t<
std::is_same_v<C, char>
>
>
operator C() const
{
return 'A';
}
template <
typename C
, typename Base = A
, typename = std::enable_if_t<
std::is_convertible_v<Base, C>
&&
!std::is_same_v<C, char>
>
>
operator C() const
{
return static_cast<C>(*static_cast<const Base*>(this));
}
};
struct AB : B
{
};
int main(){
AB ab;
int i = ab;
char c = ab;
}
我有以下代码不能用 MSVC 编译。它与 gcc、clang 和 icc 编译良好。我想这是一个错误,对吧?
你have/know有解决办法吗?
#include <type_traits>
struct A
{
template <
typename C
,typename = std::enable_if_t<std::is_same_v<C, int>>
>
operator C() const{
return 12;
}
};
struct B
{
template <
typename C
, typename = std::enable_if_t<std::is_same_v<C, char>>
, typename F = int
>
operator C() const
{
return 'A';
}
};
struct AB : A, B
{
};
int main(){
AB ab;
int i = ab;
char c = ab;
}
错误文本是:
example.cpp
<source>(34): error C2440: 'initializing': cannot convert from 'AB' to 'char'
<source>(34): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
Compiler returned: 2
我已经向 Microsoft 发布了 bug report。
在 godbolt
上查看这似乎确实是 MSVC 中的错误。在运算符模板推导过程中似乎没有考虑最后一个基数。例如
struct AB : A, B // -> only A's templated operator considered
struct AB : B, A // -> only B's templated operator considered
在您的情况下,您可以删除模板化运算符并直接使用类型 (Live)(在这种情况下使用模板无论如何都没有多大意义):
#include <type_traits>
struct A
{
operator int() const{ return 12;}
};
struct B
{
operator char() const { return 'A'; }
};
struct AB : A, B
{
};
int main(){
AB ab;
int i = ab;
char c = ab;
}
或者您可以改用 class 模板,例如 (Live):
#include <type_traits>
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
struct A
{
operator T() const{
return 12;
}
};
template <typename T, typename = std::enable_if_t<std::is_same_v<T,char>>>
struct B
{
operator T() const
{
return 'A';
}
};
struct AB : A<int>, B<char>
{
};
int main(){
AB ab;
int i = ab;
char c = ab;
}
或者您可以在单个 class (Live):
中重载模板化运算符struct A
{
template <
typename C
, typename = std::enable_if_t<std::is_same_v<C, int>>
>
operator C() const {
return 12;
}
template <
typename C
, typename = std::enable_if_t<std::is_same_v<C, char>>
, typename F = int
>
operator C() const
{
return 'A';
}
};
struct AB : A
{
};
int main() {
AB ab;
int i = ab;
char c = ab;
}
我找到了 workaround.
在这里你可以看到我的解决方案。我更改了继承层次结构并引入了转发转换运算符:
#include <type_traits>
#include <utility>
struct A
{
template <
typename C
,typename = std::enable_if_t<std::is_same_v<C, int>>
>
operator C() const{
return 12;
}
};
struct B : A
{
template <
typename C
, typename = std::enable_if_t<
std::is_same_v<C, char>
>
>
operator C() const
{
return 'A';
}
template <
typename C
, typename Base = A
, typename = std::enable_if_t<
std::is_convertible_v<Base, C>
&&
!std::is_same_v<C, char>
>
>
operator C() const
{
return static_cast<C>(*static_cast<const Base*>(this));
}
};
struct AB : B
{
};
int main(){
AB ab;
int i = ab;
char c = ab;
}