标签: declval

为什么libstdc++-v3中declval的实现看起来那么复杂?

下面的代码来自 libstdc++-v3 std::type_traits,它是一个实现std::declval

  template<typename _Tp, typename _Up = _Tp&&> // template 1
    _Up
    __declval(int);
  template<typename _Tp> // template 2
    _Tp
    __declval(long);
  template<typename _Tp> // template 3
    auto declval() noexcept -> decltype(__declval<_Tp>(0));
Run Code Online (Sandbox Code Playgroud)

但我认为我可以declval简单地实现:

template <typename T> T declval();
Run Code Online (Sandbox Code Playgroud)

这是我的测试代码:

#include <iostream>
using namespace std;

struct C {
    C() = delete;
    int foo() { return 0; }
};

namespace test {
template <typename T> T declval();
};// namespace test

int main() {
    decltype(test::declval<C>().foo()) n = 1;
    cout …
Run Code Online (Sandbox Code Playgroud)

c++ templates decltype c++11 declval

49
推荐指数
2
解决办法
2259
查看次数

我们如何测试是否可以使用prvalue调用某个类型的表达式?

使用我们看到了新的is_invocable和花哨的新prvalues,它们并不是真正的价值.

这允许您创建一个对象而无需首先在逻辑上构造它,然后忽略构造.

我遇到了一个问题,std::is_invocable用于测试你是否可以调用某些内容,而prvalue规则似乎会发生冲突:

struct no_move {
  no_move(no_move&&)=delete;
  explicit no_move(int) {}
};
void f( no_move ) {}
Run Code Online (Sandbox Code Playgroud)

现在我们可以问一下是否f可以使用类型的prvalue调用no_move

f( no_move(1) )
Run Code Online (Sandbox Code Playgroud)

std::is_invocable< decltype(&f), no_move >不起作用,因为它使用的std::declval<no_move>()是xvalue,no_move&&而不是类型的prvalue no_move.

这是相同的,但保证省略使得一些函数可以用xvalue(即" T&&")调用,而其他函数可以用prvalues类型调用T.

有替代方案,还是我们必须发明自己的特性来处理这种情况?

(在一个理论的世界里std::declval<T>返回T,而不是T&&,is_invocable会的,我相信,做正确的事).

c++ c++17 prvalue declval invocable

15
推荐指数
2
解决办法
477
查看次数

了解declval优化的实现

查看libstdc ++源代码,我发现以下declval实现:

template<typename _Tp, typename _Up = _Tp&&>
_Up __declval(int);  // (1)

template<typename _Tp>
_Tp __declval(long); // (2)

template<typename _Tp>
auto declval() noexcept -> decltype(__declval<_Tp>(0));
Run Code Online (Sandbox Code Playgroud)

此实现 Eric Niebler 提出的,用于优化编译时间:他解释说,重载解析比模板实例化更快。

但是,我不明白它是如何工作的。特别:

  1. 在(1)中,为什么使用_Up不仅仅是返回_Tp&&
  2. 似乎从未使用过重载(2)。为什么需要它?

与最幼稚的实现相反,这一切如何防止模板实例化:

template<typename T>
T&& declval() noexcept;
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer c++11 template-instantiation declval

14
推荐指数
1
解决办法
201
查看次数

std :: declval vs crtp,无法从不完整类型推断出方法返回类型

我正在尝试做这样的事情(在c ++ 11中):

#include <utility>

template <typename T>
struct base {
    using type = decltype( std::declval<T>().foo() );
};

struct bar : base<bar> {
    int foo() { return 42;}
};

int main() {
    bar::type x;
}
Run Code Online (Sandbox Code Playgroud)

失败与

prog.cc: In instantiation of 'struct base<bar>':
prog.cc:8:14:   required from here
prog.cc:5:46: error: invalid use of incomplete type 'struct bar'
     using type = decltype( std::declval<T>().foo() );
                            ~~~~~~~~~~~~~~~~~~^~~
prog.cc:8:8: note: forward declaration of 'struct bar'
 struct bar : base<bar> {
        ^~~
Run Code Online (Sandbox Code Playgroud)

如何声明bar::fooin 的返回类型的别名base …

c++ crtp decltype c++11 declval

12
推荐指数
1
解决办法
229
查看次数

T 是否必须是一个完整的类型才能在 `std::declval&lt;T&gt;` 中使用?

考虑这个例子(来自这里):

#include <type_traits>
#include <iostream>
template <typename U>
struct A {
};

struct B {
   template <typename F = int>
   A<F> f() { return A<F>{}; }

   using default_return_type = decltype(std::declval<B>().f());
};

int main()
{
    B::default_return_type x{};
    std::cout << std::is_same< B::default_return_type, A<int>>::value;
}
Run Code Online (Sandbox Code Playgroud)

在 gcc9.2 上编译没有错误,但 gcc7.2 和 clang 10.0.0 抱怨B不完整。Clangs 错误是:

prog.cc:11:58: error: member access into incomplete type 'B'
   using default_return_type = decltype(std::declval<B>().f());
                                                         ^
prog.cc:7:8: note: definition of 'B' is not complete until the …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer incomplete-type declval

12
推荐指数
2
解决办法
583
查看次数

std::reference_wrapper,构造函数实现解释

我一直试图从这里std::reference_wrapper理解 的实现,如下:

namespace detail {
template <class T> constexpr T& FUN(T& t) noexcept { return t; }
template <class T> void FUN(T&&) = delete;
}
 
template <class T>
class reference_wrapper {
public:
  // types
  typedef T type;
 
  // construct/copy/destroy
  template <class U, class = decltype(
    detail::FUN<T>(std::declval<U>()),
    std::enable_if_t<!std::is_same_v<reference_wrapper, std::remove_cvref_t<U>>>()
  )>
  constexpr reference_wrapper(U&& u) noexcept(noexcept(detail::FUN<T>(std::forward<U>(u))))
    : _ptr(std::addressof(detail::FUN<T>(std::forward<U>(u)))) {}
  reference_wrapper(const reference_wrapper&) noexcept = default;
 
  // assignment
  reference_wrapper& operator=(const reference_wrapper& x) noexcept = default;
 
  // access
  constexpr operator T& () const …
Run Code Online (Sandbox Code Playgroud)

c++ templates decltype reference-wrapper declval

8
推荐指数
1
解决办法
836
查看次数

在未评估的上下文中在 lambda 中使用 std::declval 是否合法?

下面的代码或在godbolt上的代码可以使用 gcc 和 MSVC 进行编译,但会因 clang 失败。我找不到标准中是否/哪里禁止它。我认为应该支持。

那么,clang 和 gcc/MSVC 谁的说法是正确的呢?

#include <type_traits>

void foo() {
    static_assert(decltype([_=std::declval<int>()]() consteval noexcept { // clang error: declval() must not be used
        if constexpr (std::is_integral<decltype(_)>::value) {
            return std::bool_constant<true>();
        } else {
            return std::bool_constant<false>();
        }
    }())::value);
}
Run Code Online (Sandbox Code Playgroud)

该示例可以扩展为以下 3 种情况或在godbolt上:

  1. 作为 lambda 调用参数:可以使用 clang/gcc/MSVC
  2. 作为 lambda 捕获:gcc/MSVC 正常,clang 错误
  3. 在 lambda 主体中:clang/gcc/MSVC 错误

因此,很明显,它在 lambda 主体中不合法,但在外部作为调用者参数是合法的。目前尚不清楚捕获列表中是否允许。

#include <type_traits>

auto foo_lambda_argument() {
    return decltype([](auto _) noexcept {
        return std::bool_constant<std::is_integral<decltype(_)>::value>();
    }(std::declval<int>()))::value; // OK …
Run Code Online (Sandbox Code Playgroud)

c++ lambda language-lawyer c++20 declval

8
推荐指数
1
解决办法
251
查看次数

将 declval 与引用类型一起使用

我看到一些代码示例,其中用于实例化模板函数的类型std::declval被指定为引用类型而不仅仅是类型,如下所示:

std::declval<T &>()
Run Code Online (Sandbox Code Playgroud)

与以下相反:

std::declval<T>()
Run Code Online (Sandbox Code Playgroud)

T某种类型在哪里。我忽略了为什么可以选择引用符号而不是普通类型的微妙之处。有人可以向我解释一下吗?

我知道它std::declval会扩展为,typename std::add_rvalue_reference<T>::type但我仍然不明白为什么人们会通过引用类型而不是普通类型本身来实例化后者。

c++ reference c++11 declval

6
推荐指数
1
解决办法
569
查看次数

std :: declval &lt;T&gt;()`没有匹配功能是什么原因?

我很惊讶地发现,对于某些人T,这decltype(std::declval<T>())是不合法的:

#include <utility>

template<typename T>
using Alias = decltype(std::declval<T>());

// as expected
using A1 = Alias<int>;
using A2 = Alias<int(int)>;

// error: no matching function for call to 'declval<...>()'
using A3 = Alias<int(int) const>;
using A4 = Alias<int(int) volatile>;
using A5 = Alias<int(int) &>;
using A6 = Alias<int(int) &&>;
// and all combinations of the above
Run Code Online (Sandbox Code Playgroud)

cppreference似乎并不表明该错误是预期的。

还有其他declval<T>不能使用的类型吗?规范在哪里定义这些?

c++ language-lawyer declval

3
推荐指数
1
解决办法
83
查看次数

由于保证复制省略,std::declval 是否已过时?

标准库实用程序declval定义为:

template<class T> add_rvalue_reference_t<T> declval() noexcept;
Run Code Online (Sandbox Code Playgroud)

在这里添加右值引用似乎是一个好主意,如果您考虑一下C++11 中引入的语言:返回值涉及一个临时值,该值随后被移出。现在C++17引入了保证复制省略,这不再适用。正如cppref所说:

纯右值和临时值的 C++17 核心语言规范与早期 C++ 修订版的核心语言规范根本不同:不再有临时值可以复制/移动。描述 C++17 机制的另一种方法是“非物化值传递”:返回和使用纯右值,而不会物化临时值。

这对其他以declval. 看看这个例子(在Godbolt.org查看):

#include <type_traits>

struct Class {
    explicit Class() noexcept {}    
    Class& operator=(Class&&) noexcept = delete;
};

Class getClass() {
    return Class();
}

void test() noexcept {
    Class c{getClass()}; // succeeds in C++17 because of guaranteed copy elision
}

static_assert(std::is_constructible<Class, Class>::value); // fails …
Run Code Online (Sandbox Code Playgroud)

c++ return-value-optimization copy-elision c++17 declval

3
推荐指数
1
解决办法
86
查看次数

编译器推断模板参数

template<typename T>
class A
{
    public:

    A(T &t)
    : t_(t){}

    T t_;
};


int main()
{
    int value;
    A<decltype(value)> a(value);
    // what I wish for : A a(value); 
    // which does not compile "missing template argument before 'a'"
}
Run Code Online (Sandbox Code Playgroud)

在 A (或其他地方)的声明中有没有办法提示编译器 T 应该自动解析为传递给构造函数的类型?

(理想情况下是 c++11,但很高兴听到不那么旧的版本)

c++ templates compilation decltype declval

1
推荐指数
1
解决办法
51
查看次数

无法调用 std::declval 的语句是什么意思?

cppreference-page上有std::declval以下内容:

返回值

无法调用,因此永远不会返回值。

这是什么意思?我们在使用的时候肯定会调用它吗?

struct Foo { int func(){}  };

decltype(std::declval<Foo>().func()) integer;
/*                        ^
                          |                      */ 
Run Code Online (Sandbox Code Playgroud)

c++ std declval

1
推荐指数
1
解决办法
689
查看次数