GCC称将功能与多个继承过载时,称其为模棱两可,但Clang和MSVC没有
When overloading a function with multiple inheritance, GCC says calling it is ambiguous, but Clang and MSVC do not
我正在使用此变体库:https://github.com/cbeck88/strict-variant。它提供了类似于std::variant
和boost::variant
的类。给定此struct
:
struct S
{
explicit S(double) {}
};
我想这样做:
strict_variant::variant<double, S> v = 2.0;
这与Clang 5.0.1和MSVC 19.12.25831.00一起使用,但无法与GCC 7.2.1进行编译。
我查看了库的代码,并将问题减少了:
#include <iostream>
struct S
{
constexpr S() {}
constexpr explicit S(double) {}
};
template<unsigned i> struct init_helper;
template<> struct init_helper<0> { using type = double; };
template<> struct init_helper<1> { using type = S; };
template<unsigned i>
struct initializer_leaf
{
using target_type = typename init_helper<i>::type;
constexpr unsigned operator()(target_type) const
{
return i;
}
};
struct initializer : initializer_leaf<0>, initializer_leaf<1>
{
};
int main()
{
std::cout << initializer()(double{}) << " = double" << 'n';
std::cout << initializer()(S{}) << " = S" << 'n';
return 0;
}
输出为
0 = double
1 = S
GCC说:
strict_variant_test.cpp: In function ‘int main()’:
strict_variant_test.cpp:29:37: error: request for member ‘operator()’ is ambiguous
std::cout << initializer()(double{}) << " = double" << 'n';
^
strict_variant_test.cpp:17:21: note: candidates are: constexpr unsigned int initializer_leaf<i>::operator()(initializer_leaf<i>::target_type) const [with unsigned int i = 1; initializer_leaf<i>::target_type = S]
constexpr unsigned operator()(target_type) const
^~~~~~~~
strict_variant_test.cpp:17:21: note: constexpr unsigned int initializer_leaf<i>::operator()(initializer_leaf<i>::target_type) const [with unsigned int i = 0; initializer_leaf<i>::target_type = double]
strict_variant_test.cpp:30:32: error: request for member ‘operator()’ is ambiguous
std::cout << initializer()(S{}) << " = S" << 'n';
^
strict_variant_test.cpp:17:21: note: candidates are: constexpr unsigned int initializer_leaf<i>::operator()(initializer_leaf<i>::target_type) const [with unsigned int i = 1; initializer_leaf<i>::target_type = S]
constexpr unsigned operator()(target_type) const
^~~~~~~~
strict_variant_test.cpp:17:21: note: constexpr unsigned int initializer_leaf<i>::operator()(initializer_leaf<i>::target_type) const [with unsigned int i = 0; initializer_leaf<i>::target_type = double]
但是,当我将initializer
的定义更改为:
struct initializer
{
constexpr unsigned operator()(double) const
{
return 0;
}
constexpr unsigned operator()(S) const
{
return 1;
}
};
我对C 的理解说这是同等的,所以我认为这是GCC中的一个错误,但是我经常遇到问题,标准表现出令人惊讶的事情而我的假设是错误的。所以,我的问题是:这是谁的错?GCC是否有错误?如果代码是错误的,如何修复?
这实际上是一个clang bug。
经验法则是,不同的范围中的名称不超载。这是一个简化的例子:
template <typename T>
class Base {
public:
void foo(T ) { }
};
template <typename... Ts>
struct Derived: Base<Ts>...
{};
int main()
{
Derived<int, double>().foo(0); // error
}
这应该是一个错误,因为类成员查找规则状态基本上只有一个基类可以包含一个给定的名称。如果多个基类具有相同的名称,则查找是模棱两可的。这里的分辨率是将两个 base类名称带入衍生的类中,并使用使用量表。在C 17中,使用声明可以是包装扩展,这使此问题变得更加容易:
template <typename T>
class Base {
public:
void foo(T ) { }
};
template <typename... Ts>
struct Derived: Base<Ts>...
{
using Base<Ts>::foo...;
};
int main()
{
Derived<int, double>().foo(0); // ok! calls Base<int>::foo
}
对于特定库,此代码:
template <typename T, unsigned... us> struct initializer_base<T, mpl::ulist<us...>> : initializer_leaf<T, us>... { static_assert(sizeof...(us) > 0, "All value types were inelligible!"); };
应该看起来像:
template <typename T, unsigned... us>
struct initializer_base<T, mpl::ulist<us...>> : initializer_leaf<T, us>... {
static_assert(sizeof...(us) > 0, "All value types were inelligible!");
using initializer_leaf<T, us>::operator()...; // (*) <==
};
(尽管我猜图书馆的目标是C 11,所以我提交了C 11符合条件的修复程序...这只是更多的冗长)。
相关文章:
- ArduinoJson 6.15.2:JsonObject没有命名类型
- 如果没有malloc,链表实现将失败
- 数组索引的值没有增加
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 在没有太多条件句的情况下,我如何避免被零除
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 为什么在运行时没有向我们提供有关分段错误的更多信息?
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- 变量没有改变?通过向量的函数调用
- 没有名称的C++模板参数
- 在线编译器中的分段C++没有打印消息
- 没有为自己的结构调用列表推回方法
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 没有用于初始化C++中的变量模板的匹配构造函数
- 调用'begin(int [n])'没有匹配函数
- 使用C++程序合并排序没有得到正确的输出
- 为什么在这个代码结束循环中没有得到结束
- 有没有办法将谓词中的元素偏移量传递给 std 算法?
- GCC称将功能与多个继承过载时,称其为模棱两可,但Clang和MSVC没有
- 没有函数重写的多重继承.为什么模棱两可