clang 拒绝模板 `/` 运算符,但 gnu c++ 接受它
clang rejects a template `/` operator but gnu c++ accepts it
在科学编程的单元管理上下文中,我正在管理以下内容class:
template <class UnitName>
class Quantity
{
double value;
public:
Quantity(double val = 0) : value(val) {}
Quantity(const Quantity &) {}
Quantity & operator = (const Quantity &) { return *this; }
double get_value() const noexcept { return value; }
operator double() const noexcept { return value; }
template <class SrcUnit>
Quantity(const Quantity<SrcUnit> &)
{
// here the conversion is done
}
template <class SrcUnit>
Quantity & operator = (const Quantity<SrcUnit> &)
{
// here the conversion is done
return *this;
}
template <class TgtUnit> operator TgtUnit() const
{
TgtUnit ret;
// here the conversion is done
return ret;
}
template <class U, class Ur>
Quantity<Ur> operator / (const Quantity<U> & rhs) const
{
return Quantity<Ur>(value / rhs.value);
}
};
虽然 class 复杂得多,但我想我提供了足够的信息来描述我的问题:
现在考虑以下代码片段:
struct km_h {};
struct Km {};
struct Hour {};
Quantity<km_h> compute_speed(const Quantity<Km> & dist,
const Quantity<Hour> & time)
{
Quantity<km_h> v = dist/time;
return v;
}
此代码被gnu c++
编译器接受并且运行良好。最后一个模板运算符 /
被调用。
但它被 clang++
编译器 (v 3.8.1) 拒绝并显示以下消息:
test-simple.cc:53:26: error: use of overloaded operator '/' is ambiguous (with operand
types 'const Quantity<Km>' and 'const Quantity<Hour>')
Quantity<km_h> v = dist/time;
~~~~^~~~~
test-simple.cc:53:26: note: built-in candidate operator/(__int128, unsigned long long)
test-simple.cc:53:26: note: built-in candidate operator/(unsigned long, long double)
所以我的问题是:为什么 clang++
拒绝它?是一个有效的代码?还是 gnu c++
应该拒绝?
在代码有效的情况下,如何修改它才能clang++
接受它?
我相信 clang 拒绝您的代码是正确的†,但 gcc 实际上并没有按照您的意愿进行(dist
和 time
可以隐式转换为 double
‡ 并且 gcc 认为内置 operator/(double, double)
是最可行的候选者)。问题是,你写道:
template <class U, class Ur>
Quantity<Ur> operator / (const Quantity<U> & rhs) const
什么是Ur
?这是一个非推导的上下文 - 因此尝试调用此运算符只是 dist / time
是推导失败。您的候选人从未被考虑过。为了实际使用它,您必须像这样明确提供 Ur
:
dist.operator/<Hour, km_h>(time); // explicitly providing Ur == km_h
因为那太糟糕了,你不能将 Ur
推导为模板参数 - 你必须自己提供它作为两个单元的一些元函数:
template <class U>
Quantity<some_mf_t<UnitName, U>> operator/(Quantity<U> const& ) const;
和some_mf_t
是要定义的。
†你同时拥有 operator double()
和 template <class T> operator T()
,这意味着所有内置 operator/
都是同样可行的候选者(它们' re all non-template, exact matches)。
‡ operator double()
有点违背了编写类型安全单元的目的,不是吗?
在科学编程的单元管理上下文中,我正在管理以下内容class:
template <class UnitName>
class Quantity
{
double value;
public:
Quantity(double val = 0) : value(val) {}
Quantity(const Quantity &) {}
Quantity & operator = (const Quantity &) { return *this; }
double get_value() const noexcept { return value; }
operator double() const noexcept { return value; }
template <class SrcUnit>
Quantity(const Quantity<SrcUnit> &)
{
// here the conversion is done
}
template <class SrcUnit>
Quantity & operator = (const Quantity<SrcUnit> &)
{
// here the conversion is done
return *this;
}
template <class TgtUnit> operator TgtUnit() const
{
TgtUnit ret;
// here the conversion is done
return ret;
}
template <class U, class Ur>
Quantity<Ur> operator / (const Quantity<U> & rhs) const
{
return Quantity<Ur>(value / rhs.value);
}
};
虽然 class 复杂得多,但我想我提供了足够的信息来描述我的问题:
现在考虑以下代码片段:
struct km_h {};
struct Km {};
struct Hour {};
Quantity<km_h> compute_speed(const Quantity<Km> & dist,
const Quantity<Hour> & time)
{
Quantity<km_h> v = dist/time;
return v;
}
此代码被gnu c++
编译器接受并且运行良好。最后一个模板运算符 /
被调用。
但它被 clang++
编译器 (v 3.8.1) 拒绝并显示以下消息:
test-simple.cc:53:26: error: use of overloaded operator '/' is ambiguous (with operand
types 'const Quantity<Km>' and 'const Quantity<Hour>')
Quantity<km_h> v = dist/time;
~~~~^~~~~
test-simple.cc:53:26: note: built-in candidate operator/(__int128, unsigned long long)
test-simple.cc:53:26: note: built-in candidate operator/(unsigned long, long double)
所以我的问题是:为什么 clang++
拒绝它?是一个有效的代码?还是 gnu c++
应该拒绝?
在代码有效的情况下,如何修改它才能clang++
接受它?
我相信 clang 拒绝您的代码是正确的†,但 gcc 实际上并没有按照您的意愿进行(dist
和 time
可以隐式转换为 double
‡ 并且 gcc 认为内置 operator/(double, double)
是最可行的候选者)。问题是,你写道:
template <class U, class Ur>
Quantity<Ur> operator / (const Quantity<U> & rhs) const
什么是Ur
?这是一个非推导的上下文 - 因此尝试调用此运算符只是 dist / time
是推导失败。您的候选人从未被考虑过。为了实际使用它,您必须像这样明确提供 Ur
:
dist.operator/<Hour, km_h>(time); // explicitly providing Ur == km_h
因为那太糟糕了,你不能将 Ur
推导为模板参数 - 你必须自己提供它作为两个单元的一些元函数:
template <class U>
Quantity<some_mf_t<UnitName, U>> operator/(Quantity<U> const& ) const;
和some_mf_t
是要定义的。
†你同时拥有 operator double()
和 template <class T> operator T()
,这意味着所有内置 operator/
都是同样可行的候选者(它们' re all non-template, exact matches)。
‡ operator double()
有点违背了编写类型安全单元的目的,不是吗?