consteval 方法的 decltype(fun())
decltype(fun()) for consteval methods
考虑以下代码。我可以用 GCC 10.2.0 和 Clang 11.0.0 编译它(如预期的那样):
#include <iostream>
template<int>
struct T {
static constexpr auto fun() noexcept { return 0; }
using type = std::remove_cvref_t<decltype(fun())>;
};
int main() {
decltype(T<1>::fun()) a = 1;
std::cout << a;
}
如果我将 constexpr
替换为 consteval
,则 Clang 会抱怨 std::remove_cvref_t<decltype(fun())>
:
error: cannot take address of consteval function 'fun' outside of an immediate invocation
GCC编译就好了。为什么?
如问题评论中所述,这是 CLang 错误。
只有当函数是静态方法时才会出现此错误,如果它是全局函数,则代码可以正常工作(请参阅工作 online example here)。
因此解决这个问题的一种方法是使用全局函数来转发静态方法的结果。我在下面做了一个更高级的这种全局转发的例子。
#include <iostream>
#include <type_traits>
template <typename T, typename ... Args>
static consteval auto forward_fun(Args ... args) {
return T::fun(args...);
}
template <int I>
struct T {
static consteval auto fun(int i, bool f) noexcept {
return i + 1;
}
using type = std::remove_cvref_t<decltype(forward_fun<T>(123, true))>;
};
int main() {
T<1>::type a = 1;
std::cout << a;
return 0;
}
考虑以下代码。我可以用 GCC 10.2.0 和 Clang 11.0.0 编译它(如预期的那样):
#include <iostream>
template<int>
struct T {
static constexpr auto fun() noexcept { return 0; }
using type = std::remove_cvref_t<decltype(fun())>;
};
int main() {
decltype(T<1>::fun()) a = 1;
std::cout << a;
}
如果我将 constexpr
替换为 consteval
,则 Clang 会抱怨 std::remove_cvref_t<decltype(fun())>
:
error: cannot take address of consteval function 'fun' outside of an immediate invocation
GCC编译就好了。为什么?
如问题评论中所述,这是 CLang 错误。
只有当函数是静态方法时才会出现此错误,如果它是全局函数,则代码可以正常工作(请参阅工作 online example here)。
因此解决这个问题的一种方法是使用全局函数来转发静态方法的结果。我在下面做了一个更高级的这种全局转发的例子。
#include <iostream>
#include <type_traits>
template <typename T, typename ... Args>
static consteval auto forward_fun(Args ... args) {
return T::fun(args...);
}
template <int I>
struct T {
static consteval auto fun(int i, bool f) noexcept {
return i + 1;
}
using type = std::remove_cvref_t<decltype(forward_fun<T>(123, true))>;
};
int main() {
T<1>::type a = 1;
std::cout << a;
return 0;
}