最近,我想知道如何实现像declval
这样的元功能。
我尝试过的第一件事是:
template <typename T>
constexpr auto declval() -> T&&;
这样就很好了,除了当我试图用它来创建varialbe时(我知道现在没有任何意义),我得到了链接器错误,这很明显,因为该函数没有正文
auto varName = declval<int>(); // linker error
decltype(declval<int>()) varName2 = 5; // works fine
尽管如此,原始的实现(从gcc版本开始)是否会以相同的方式表现(给我链接器错误)。事实证明,他们尝试使用declval
来创建变量时,其静态断言看起来或多或少像:
static_assert(__declval_protector<T>::stop, "error message");
这令我惊讶。我想实现完全相同的行为。我的第一次尝试是:
template <typename T>
auto declval() -> T&&{static_assert(false, "error message")}
我认为,也许在declval
上下文中使用decltype
时,根本就不需要它的主体,所以也许编译器会跳过它,如果我试图创建变量,它将做static_assert
,因为declval
的身体很关键
那不是事实。我总是遇到static_assert
错误,无法使用declval
编译任何程序。我以为我会尝试以与标准库相同的方式实现它。最后,在同事的帮助下,我们实现了以下实现:
template <typename T>
struct Protector{
const static bool stop=false;
};
template <typename T>
constexpr auto declval() -> T&&
{
static_assert(Protector<T>::stop, "You cannot do it");
}
这完全正常。与标准库版本完全相同。但是为什么这样做有效,对我来说完全是个谜。
谁能解释我第二种实现在C ++中如何工作?对我来说,它应该执行与static_assert
上下文相同的decltype
错误,但显然不会。
实现方式不同的原因是什么。