转换为否定的一元表达式在函数模板中失败
Cast to negated unary expression fails in function templates
我使用下面的代码来比较算术类型。 class 模板 equal
比较给定参数是否相等,并将结果存储在成员变量 result
中。 class 模板还为 bool
提供了一个转换运算符,以便在条件语句中进行评估。我还提供了一个模板推导指南,以便在构造 equal
对象时不必手动转换参数。当 equal
从非模板函数求值时,这总是有效,但当表达式被 operator!()
否定时,在函数模板中编译失败,至少在当前的 clang 编译器 (11.0.1) 上是这样。但是,它使用 gcc 和 msvc 编译。代码示例中,函数模板dummy()
:
编译失败
#include <algorithm>
#include <concepts>
#include <limits>
#include <type_traits>
template<typename T>
inline constexpr auto abs(T value) -> T
{
if (value < 0)
return -1 * value;
return value;
}
template<std::integral T>
inline constexpr auto integersEqual(const T lref, const T rref) noexcept -> bool
{
return lref == rref;
}
template<std::floating_point T>
inline constexpr auto floatingPointsEqual(const T lref, const T rref) noexcept -> bool
{
constexpr T epsilon = std::numeric_limits<T>::epsilon() * 1000;
return abs(lref - rref) <=
(epsilon * std::max<T>(abs(lref), abs(rref)));
}
template<typename T>
inline constexpr auto arithmeticEqual(const T lref, const T rref) noexcept -> bool
{
if constexpr (std::is_integral_v<T>)
{
return integersEqual(lref, rref);
}
else
{
return floatingPointsEqual(lref, rref);
}
}
template<typename T>
class equal final
{
public:
inline constexpr equal(const T lref, const T rref) noexcept : result(arithmeticEqual(lref, rref)) {}
inline constexpr operator bool() const noexcept
{
return result;
}
inline constexpr auto operator!() const noexcept -> bool
{
return !result;
}
private:
const bool result;
};
// deduction guides for equal
template<typename T1, typename T2>
equal(T1, T2) -> equal<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>;
template<typename T1, typename T2>
auto dummy(const T1 t1, const T2 t2) -> bool
{
return !equal(t1, t2); // <- This line fails. If not negated, it works
//return equal(t1, t2) == false; // this works
//return !equal<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>(t1, t2); // this works as well
}
auto main() -> int
{
return dummy(12, 13);
}
(Link 到编译器资源管理器:https://godbolt.org/z/PMcMab)
编译失败并显示以下错误消息:
<source>:67:12: error: invalid argument type 'equal' to unary expression
return !equal(t1, t2);
将 operator!()
添加到 class 模板 equal
无法解决此问题。我的问题是:为什么 clang 不接受这段代码?我没有看到这段代码有问题。这是 clang 中的错误吗?通常 clang 比其他编译器更严格地遵循标准,所以我想知道 gcc 和 msvc 是否都接受了这段代码,但实际上不应该。我怀疑模板参数推导是罪魁祸首,因为提供具体的模板参数可以解决问题。是否由于某种我不知道的原因扣减失败?
我有点认为这是 clang 中的一个错误。我摆弄了一会儿。
我试过了:
return equal( t1, t2 ).operator !();
哪个 clang 不喜欢,但其他编译器喜欢。
叮当说:
<source>:69:27: error: member reference base type 'equal' is not a structure or union
return equal( t1, t2 ).operator !();
一个有趣的错误。
此外,如果您这样做:
bool dummy2( int t1, unsigned t2)
{
return !equal(t1, t2);
}
编译正常。所以它与推导指南结合在模板方法中调用推导指南。
最后,编译:
template<typename T1, typename T2>
auto dummy(const T1 t1, const T2 t2) -> bool
{
typedef decltype( equal(t1, t2) ) _TyEqual;
static_assert( std::is_same_v< _TyEqual, equal< std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>> );
return !_TyEqual(t1, t2);
}
加上其他错误,我认为错误是 clang 在应用推导指南时使用了某种中间类型。一旦你拼出 clang 的类型,它就会喜欢它...
无论如何,这个问题很有趣,我在这个过程中获得了一些关于演绎指南的知识。
我使用下面的代码来比较算术类型。 class 模板 equal
比较给定参数是否相等,并将结果存储在成员变量 result
中。 class 模板还为 bool
提供了一个转换运算符,以便在条件语句中进行评估。我还提供了一个模板推导指南,以便在构造 equal
对象时不必手动转换参数。当 equal
从非模板函数求值时,这总是有效,但当表达式被 operator!()
否定时,在函数模板中编译失败,至少在当前的 clang 编译器 (11.0.1) 上是这样。但是,它使用 gcc 和 msvc 编译。代码示例中,函数模板dummy()
:
#include <algorithm>
#include <concepts>
#include <limits>
#include <type_traits>
template<typename T>
inline constexpr auto abs(T value) -> T
{
if (value < 0)
return -1 * value;
return value;
}
template<std::integral T>
inline constexpr auto integersEqual(const T lref, const T rref) noexcept -> bool
{
return lref == rref;
}
template<std::floating_point T>
inline constexpr auto floatingPointsEqual(const T lref, const T rref) noexcept -> bool
{
constexpr T epsilon = std::numeric_limits<T>::epsilon() * 1000;
return abs(lref - rref) <=
(epsilon * std::max<T>(abs(lref), abs(rref)));
}
template<typename T>
inline constexpr auto arithmeticEqual(const T lref, const T rref) noexcept -> bool
{
if constexpr (std::is_integral_v<T>)
{
return integersEqual(lref, rref);
}
else
{
return floatingPointsEqual(lref, rref);
}
}
template<typename T>
class equal final
{
public:
inline constexpr equal(const T lref, const T rref) noexcept : result(arithmeticEqual(lref, rref)) {}
inline constexpr operator bool() const noexcept
{
return result;
}
inline constexpr auto operator!() const noexcept -> bool
{
return !result;
}
private:
const bool result;
};
// deduction guides for equal
template<typename T1, typename T2>
equal(T1, T2) -> equal<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>;
template<typename T1, typename T2>
auto dummy(const T1 t1, const T2 t2) -> bool
{
return !equal(t1, t2); // <- This line fails. If not negated, it works
//return equal(t1, t2) == false; // this works
//return !equal<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>(t1, t2); // this works as well
}
auto main() -> int
{
return dummy(12, 13);
}
(Link 到编译器资源管理器:https://godbolt.org/z/PMcMab)
编译失败并显示以下错误消息:
<source>:67:12: error: invalid argument type 'equal' to unary expression
return !equal(t1, t2);
将 operator!()
添加到 class 模板 equal
无法解决此问题。我的问题是:为什么 clang 不接受这段代码?我没有看到这段代码有问题。这是 clang 中的错误吗?通常 clang 比其他编译器更严格地遵循标准,所以我想知道 gcc 和 msvc 是否都接受了这段代码,但实际上不应该。我怀疑模板参数推导是罪魁祸首,因为提供具体的模板参数可以解决问题。是否由于某种我不知道的原因扣减失败?
我有点认为这是 clang 中的一个错误。我摆弄了一会儿。
我试过了:
return equal( t1, t2 ).operator !();
哪个 clang 不喜欢,但其他编译器喜欢。
叮当说:
<source>:69:27: error: member reference base type 'equal' is not a structure or union
return equal( t1, t2 ).operator !();
一个有趣的错误。
此外,如果您这样做:
bool dummy2( int t1, unsigned t2)
{
return !equal(t1, t2);
}
编译正常。所以它与推导指南结合在模板方法中调用推导指南。
最后,编译:
template<typename T1, typename T2>
auto dummy(const T1 t1, const T2 t2) -> bool
{
typedef decltype( equal(t1, t2) ) _TyEqual;
static_assert( std::is_same_v< _TyEqual, equal< std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>> );
return !_TyEqual(t1, t2);
}
加上其他错误,我认为错误是 clang 在应用推导指南时使用了某种中间类型。一旦你拼出 clang 的类型,它就会喜欢它...
无论如何,这个问题很有趣,我在这个过程中获得了一些关于演绎指南的知识。