根据https://en.cppreference.com/w/cpp/utility/declval,declval
的可能实现如下:
template<typename T>
constexpr bool always_false = false;
template<typename T>
typename std::add_rvalue_reference<T>::type declval() noexcept
{
static_assert(always_false<T>, "declval not allowed in an evaluated context");
}
我试图用std::add_rvalue_reference<Test>::type
替换std::declval<T>()
的用例,但它无法编译。为什么会这样呢?
以下是我的测试代码片段:
#include <iostream>
#include <type_traits>
#include <utility>
struct Test {
int func() {
return 1;
}
};
template<typename T>
constexpr bool always_false = false;
template<typename T>
typename std::add_rvalue_reference<T>::type Decltype() noexcept
{
static_assert(always_false<T>, "declval not allowed in an evaluated context");
}
int main() {
if (std::is_same_v<decltype(std::add_rvalue_reference<Test>::type.func()),int>) {
std::cout <<"same\n";
} else {
std::cout <<"different\n";
}
}
3条答案
按热度按时间fnx2tebb1#
你需要一个
type
的示例来检查非static
成员函数func
返回什么:或
但是,除非
type
是默认的可构造和可破坏的,否则这将不起作用。你可以使用自己的Decltype
函数模板来解决这个问题:或者,以
Test*
开头:注:
Decltype
是一个误导性的名称。Declval
更有意义。ddarikpa2#
问题是
decltype(std::add_rvalue_reference<Test>::type
是类型,而您试图调用该类型的函数,这是不允许的。成员访问
operator.
将一个类对象作为其左操作数,但在您的示例中并非如此。要解决这个问题,可以创建结果类型的对象,然后使用该对象调用成员函数。
fsi0uk1n3#
decltype(unevaluded_expresssion)
应该给予其操作数的编译时类型-而不计算(评估)操作数。因此,unevaluded_expresssion
应该是一个表达式,结果是一个值(与类型相反),但它实际上并没有作为使用decltype
的结果进行计算。现在,我们如何告诉编译器表达式应该有一个由特定类型的假设,未指定/一般值组成的子表达式?
假设要求编译器“查找结果类型of将类型为
C
的对象添加到类型为B
的对象,并将其命名为my_type
**。假设我们将在隐式会话之后包括加法到适当类型。你是怎么作曲的?第一次尝试:
上面的问题是它要求
B
和C
都是默认可构造的。如果它们中的一个或两个都缺少默认构造函数怎么办?如果这两种类型的属性都是已知的,则可以尝试查找有效的表达式来生成这两种类型的值。如果类型
B
和C
在模板定义中作为依赖/参数类型出现,该怎么办?你不再知道如何构造一个表达式来得到正确类型的值了吗?!更好的尝试是:
std::declval<X>()
仅表示类型X的虚构值。如果没有像std::declval
这样的东西,你就无法表达这一点。requires
子句是唯一的例外,但这是另一个非常长的故事。