我有一些代码使用模板转换运算符来查找通过 ADL 找到的函数的返回类型。
简化的代码如下所示:
#include <type_traits>
template<typename S>
struct probe {
template<typename T, typename U = S, std::enable_if_t<
std::is_same<T&, U>::value &&
!std::is_const<T>::value, int> = 0>
operator T& ();
template<typename T, typename U = S&&, std::enable_if_t<
std::is_same<T&&, U>::value &&
!std::is_const<T>::value, int> = 0>
operator T&& ();
template<typename T, typename U = S, std::enable_if_t<
std::is_same<T const&, U>::value, int> = 0>
operator T const& () const;
template<typename T, typename U = S&&, std::enable_if_t<
std::is_same<T const&&, U>::value, int> = 0>
operator T const&& () const;
};
namespace foo {
struct bar {};
auto find_me(bar const&) -> int { return 0; }
}
int main() {
// That would be inside a template in my code.
find_me(probe<foo::bar>{});
}
在 clang 6 和 GCC 中,上面的代码可以编译。但是,在 Clang 7 中,它不再编译了!
如您所见,clang 6 解决了对的调用,probe<foo::bar>::operator foo::bar&&<foo::bar, foo::bar&&, 0>()
但 clang 7 失败,因为它尝试调用probe<foo::bar>::operator const foo::bar&&<const foo::bar, foo::bar&&, 0>()
哪个编译器是对的?标准中的规则是什么?这是一个新的 Clang 错误还是修复?
我想检查很多情况。不仅foo::bar
作为参数,还有许多引用类型,例如:
namespace foo {
struct bar {};
auto find_me(bar const&) -> int { return 0; }
auto find_me(bar&&) -> int { return 0; }
auto find_me(bar const&&) -> int { return 0; }
auto find_me(bar&) -> int { return 0; }
}
int main() {
find_me(probe<foo::bar>{});
find_me(probe<foo::bar&>{});
find_me(probe<foo::bar&&>{});
find_me(probe<foo::bar const&>{});
find_me(probe<foo::bar const&&>{});
}
解决正确的函数调用很重要。
这是所有这些情况的一个活生生的例子,GCC 成功但 clang 失败:https ://godbolt.org/z/yrDFMg