C++ 在函数模板中转换为否定的一元表达式失败

C++ 在函数模板中转换为否定的一元表达式失败,c++,templates,template-argument-deduction,unary-operator,typecast-operator,C++,Templates,Template Argument Deduction,Unary Operator,Typecast Operator,我使用以下代码来比较算术类型。类模板equal比较给定的相等参数,并将结果存储在成员变量result中。类模板还为bool提供了一个cast操作符,以便在条件语句中进行计算。我还提供了一个模板推导指南,以便在构造equal对象时不必手动强制转换参数。当从非模板函数中计算equal时,此方法始终有效,但当表达式被运算符求反时,无法在函数模板中编译!(),至少在当前的clang编译器(11.0.1)上。但是,它是用gcc和msvc编译的。在代码示例中,函数模板dummy()中的编译失败: #包括)

我使用以下代码来比较算术类型。类模板
equal
比较给定的相等参数,并将结果存储在成员变量
result
中。类模板还为
bool
提供了一个cast操作符,以便在条件语句中进行计算。我还提供了一个模板推导指南,以便在构造
equal
对象时不必手动强制转换参数。当从非模板函数中计算
equal
时,此方法始终有效,但当表达式被
运算符求反时,无法在函数模板中编译!()
,至少在当前的clang编译器(11.0.1)上。但是,它是用gcc和msvc编译的。在代码示例中,函数模板
dummy()
中的编译失败:

#包括)

编译失败,并显示以下错误消息:

<source>:67:12: error: invalid argument type 'equal' to unary expression
    return !equal(t1, t2); 
:67:12:错误:一元表达式的参数类型“equal”无效
回来!相等(t1,t2);

添加
操作符!()
到类模板
equal
不能解决此问题。我的问题是:为什么clang不接受这个代码?我看这个代码没有问题。这是叮当作响的虫子吗?通常,clang比其他编译器更严格地遵循该标准,因此我想知道gcc和msvc是否都接受该代码,但实际上不应该接受。我怀疑模板参数推断是罪魁祸首,因为提供一个具体的模板参数可以解决这个问题。扣除失败是因为我不知道的原因吗?

我有点认为这是一个叮当作响的错误。我把这个摆弄了一会儿

我试过:

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 !();
它编译得很好。因此,它与演绎指南以及模板方法内部的演绎指南调用有关

最后,这将编译:

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);
}
模板
自动虚拟(常数T1 T1,常数T2)->bool
{
typedef decltype(相等(t1,t2))TyEqual;
静态断言(std::is_same_v<\u TyEqual,equal>);
返回!等于(t1,t2);
}
再加上其他错误,我认为错误在于clang在应用演绎指南时使用了某种中间类型。一旦你把字型拼出来,它就会喜欢它


无论如何,这是一个有趣的问题,在这个过程中,我获得了一些关于演绎指南的知识。

不是解决方案,而是一个观察:使用另一个自定义名称作为演绎指南可以很好地编译clang.return!静态施法(等于(t1,t2));解决了调用方的问题,但在没有它的情况下应该可以工作,因为lambda显式声明了布尔返回类型。对我来说,这个叮当声似乎有点问题。@Secundi你能解释一下你所说的“自定义名称”是什么意思吗?我不知道在演绎指南中可以使用与正在演绎的模板不同的名称。当我试图重新命名演绎指南时,它没有编译。语法是什么?您可以编写
template constexpr auto custom_equal(T1,T2)->equal如果我尝试您的示例,我会得到以下错误(这是有意义的):“忽略候选模板:无法推断模板参数'U1'constexpr auto custom_equal(T1,T2)->equal;”当我删除参数U1和U2时,我得到警告“警告:未定义内联函数'custom_equal'[-Wundefined inline]constexpr auto custom_equal(T1,T2)->equal;”,并且可以在程序集中看到clang将dummy中的调用解释为函数调用。错误消息确实非常有趣。我在类equal中添加了以下方法:“inline constexpr auto b()->bool{return result;}”,当我尝试在虚拟模板中以“return equal(t1,t2).b();”的形式调用此方法时,我收到了相同的错误消息,关于equal不是一个结构或并集。如果我将结果存储在一个临时变量中,并调用方法b(),它就会工作。现在对我来说真的像个叮当作响的虫子。我同意。你会给他们一只虫子吗?是的,我很快就会给他们一只虫子。由于在llvm bug跟踪器上的自我注册被禁用,我不得不等待他们批准我的注册。我刚收到他们的一封邮件,因此我将首先搜索bug跟踪器以查找此错误,如果我认为此问题尚未报告,请将此示例缩减到最低限度并提交。在我提交之后,我会在这里发布错误通知单的链接,如果他们认为这是一个错误,接受你的回答为“解决方案”。再次感谢您的宝贵提示。当我为bug追踪器提供一个缩小的示例时,我还尝试使用当前的主干clang编译代码,这很有效。我想我应该事先试一试。在我看来,这个问题已经得到了解决,所以我不会为这个问题创建新的错误记录,而是希望下一个版本(可能是11.0.2)能够解决这个问题。不管怎样,我们都会努力工作。
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);
}