使用CRTP模式时来自继承的模棱两可的方法 [英] Ambiguous method from inheritance when using a CRTP pattern
问题描述
我正在定义一个DoubleWrapper
类,该类继承自两个CRTP基类Ratioable
和Divable
,这两个基类都定义了具有不同签名的operator/()
:
I am defining a DoubleWrapper
class inheriting from two CRTP base classes, Ratioable
and Divable
, that both define operator/()
, with different signatures:
T operator/(double const& scalar) const { return T(this->underlying().get() / scalar); }
double operator/(T const& other) const { return this->underlying().get() / other.get(); }
它们在返回类型和参数类型上都不同.但是,编译器抱怨operator/()模棱两可.请注意,构造函数是显式的,因此不会从double转换为DoubleWrapper.
They differ both by return type and parameter type. However compiler is complaining about operator/() being ambiguous. Note that the constructor is explicit so there is no ambiguous conversion from double to DoubleWrapper.
- 在Visual Studio 2017上,它可以正常运行并且可以正常运行,但是我在代码中获得了一个工具提示,使用多个运算符"/"匹配这些操作数:(...)".如果我重命名运算符以使其成为常规方法(
divide
(...)),则会出现编译错误:
- On Visual Studio 2017 it is compiling and running fine however I get a tooltip in the code "more than one operator "/" matches those operands: (...)" at the place of use. If I rename the operator to make it a regular method (
divide
(...)), I get a compile error :
错误C2385:划分"的模棱两可的访问 注意:可能是基本可划分"中的划分" 注意:或者可以是基于比率"的分度"
error C2385: ambiguous access of 'divide' note: could be the 'divide' in base 'Divable' note: or could be the 'divide' in base 'Ratioable'
-
即使使用操作员版本,G ++ 6.2也会给我一个编译错误:
G++ 6.2 gives me a compile error even with the operator version:
错误:成员"operator/"的请求不明确 双b = a/a; ^ 注意:候选者是:double Ratioable :: operator/(const T&)const [with T = DoubleWrapper] 双重运算符/(T const& val)const {返回this-> underlying().get()/val.get(); } ^ ~~~~~~~~ 注意:T Divable :: operator/(const double&)const [with T = DoubleWrapper] T运算符/(double const& val)const {return T(this-> underlying().get()/val); } ^ ~~~~~~~
error: request for member ‘operator/’ is ambiguous double b = a / a; ^ note: candidates are: double Ratioable::operator/(const T&) const [with T = DoubleWrapper] double operator/(T const& val) const { return this->underlying().get() / val.get(); } ^~~~~~~~ note: T Divable::operator/(const double&) const [with T = DoubleWrapper] T operator/(double const& val) const { return T(this->underlying().get()/ val); } ^~~~~~~~
C ++允许具有相同名称的方法,只要它们具有不同的签名即可.歧义从何而来?
C++ allows methods with the same name as long as they have different signatures. Where is the ambiguity coming from ?
测试代码:
DoubleWrapper a(10.);
double b = a / (a/2.); // Both operator/ should be called. I would expect b value to be 2.
源代码:
/* Curiously Recurring Template Pattern */
template <typename T, template<typename> class crtpType>
struct crtp
{
T& underlying() { return static_cast<T&>(*this); }
T const& underlying() const { return static_cast<T const&>(*this); }
};
/* Inheriting class can be divided by a scalar */
template<typename T>
struct Divable : crtp<T, Divable>
{
T operator/(double const& scalar) const { return T(this->underlying().get() / scalar); }
};
/* Inheriting class can be divided by itself */
template<typename T>
struct Ratioable : crtp<T, Ratioable>
{
double operator/(T const& other) const { return this->underlying().get() / other.get(); }
};
struct DoubleWrapper :
public Divable<DoubleWrapper>,
public Ratioable<DoubleWrapper>
{
explicit DoubleWrapper(double val) : val_(val) {}
double get() const { return val_; }
private:
double val_;
};
推荐答案
名称解析在重载解析之前完成.
Name resolution is done before overload resolution.
DoubleWrapper
中没有operator/
,因此编译器会在其基类中查找operator/
,并在使该名称模糊不清的情况下找到一个(c)(并且不会进行重载解析).
There are no operator/
in DoubleWrapper
so the compiler goes looking for operator/
in it's base classes and finds one in both making the name ambiguous (and no overload resolution takes place).
您可以使用using
解决名称解析:
You may resolve name resolution with using
:
struct DoubleWrapper :
public Divable<DoubleWrapper>,
public Ratioable<DoubleWrapper>
{
using Divable<DoubleWrapper>::operator/;
using Ratioable<DoubleWrapper>::operator/;
explicit DoubleWrapper(double val) : val_(val) {}
double get() const { return val_; }
private:
double val_;
};
有趣的读物:
https://en.wikipedia.org/wiki/Dominance_(C++)
http://en.cppreference.com/w/cpp/language/unqualified_lookup
这篇关于使用CRTP模式时来自继承的模棱两可的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!