gpt4 book ai didi

c++ - clang 是否有权根据其重载之一拒绝具有尾随 decltype 返回类型的模板调用?

转载 作者:搜寻专家 更新时间:2023-10-31 02:07:02 26 4
gpt4 key购买 nike

我很惊讶地看到 clang 无法编译以下 c++11 代码:

#include <type_traits>

template<class T>
struct A {};

template<class T>
struct B : A<T> { T x; };

template<class T>
const typename std::remove_reference<T>::type& add_const(T&& x) { return x; }

template<class T>
T& cast_away_const(const T& x) { return const_cast<T&>(x); }

template<class T>
const B<T>& downcast(const A<T>& x) { return static_cast<const B<T>&>(x); }

template<class T>
auto downcast(A<T>& a) ->
decltype(cast_away_const(downcast(add_const(a)))) {
return cast_away_const(downcast(add_const(a)));
}

int main() {
B<int> b;
b.x = 42;
A<int>& a = b;
B<int>& b_again = downcast(a);
return b_again.x;
}

更准确地说,clang 3.7.1 提示模板实例化链很长,表现得好像 auto downcast(A<T>& a) -> /*...*/ 的实例化与 T=int需要自身的实例化。clang 5.0.0 或 6.0.0 只会崩溃(!)。gcc 和 msvc 都接受。

godbolt link

现在,clang-5.0.0 崩溃显然是一个错误,但 clang-3.7.1 错误是有道理的,所以……首先,该代码是否合法?

让我强调一下,我问的是这段代码是否合法,而不是解决方法(一个简单的解决方法是将 overload 拆分为 overloadoverload_const ,让后者仅处理 const 引用并具有前者称后者)。

我可以在 clang 和 gcc 之间找到以下有点相关的争论点 (trailing return type using decltype with a variadic template function, SO link)除了这个类似的问题,其答案引用了标准 (gcc can compile a variadic template while clang cannot)然而,我不确定这里是否适用完全相同的论点(因为 downcast 应该引用先前声明的重载,而不是尾随返回类型中的自身)。

最佳答案

所以第一件事是downcast可以通过 ADL 在 A<T> 上找到因为它在关联的命名空间中。

所以在这里:

template<class T>
auto downcast(A<T>& a) ->
decltype(cast_away_const(downcast(add_const(a))))

在确定自身的返回类型时必须考虑自身。如果它在不同的命名空间中,则不允许将自己视为可能的重载候选对象。

所以这是一个简单的解决方案;将两个重载移动到 details .也许在同一个命名空间中有一个助手 A转发到详细信息版本。

显然 msvc 和 gcc 注意到 const&在完全重新评估非常量版本的返回类型之前,重载将是一个更好的选择。

details {
template<class T>
const B<T>& downcast(const A<T>& x) { return static_cast<const B<T>&>(x); }

template<class T>
auto downcast(A<T>& a) ->
decltype(cast_away_const(details::downcast(add_const(a)))) {
return cast_away_const(details::downcast(add_const(a)));
}
}
template<class X,
std::enable_if_t< /* A<T> is a base of X for some T */, bool> =true
>
auto downcast(X&& x)
-> decltype(details::downcast(std::forward<X>(x)))
{ return details::downcast(std::forward<X>(x)); }

我不知道 clang 将代码视为格式错误的程序是否正确。

关于c++ - clang 是否有权根据其重载之一拒绝具有尾随 decltype 返回类型的模板调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49276922/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com