5

Can somebody explain how does std::declval work? I've found this implementation inside gcc headers/type_traits (lines 2248-2262), which is (cleared up a bit to improve readability):

template<typename _Tp>
struct __declval_protector
{
    static const bool __stop = false;
    static typename add_rvalue_reference<_Tp>::type __delegate();
};

template<typename _Tp>
typename add_rvalue_reference<_Tp>::type
declval ()
{
    static_assert(__declval_protector<_Tp>::__stop, "declval() must not be used!");
    return __declval_protector<_Tp>::__delegate();
}

I don't understand the part return __declval_protector<_Tp>::__delegate(), does it call the default initializer for an Rvalue reference of type T? Also i don't understand why the static_assert is not called every time I call declval, since __stop is always false (And how can it distinguish between unevaluated contexts and evaluated ones?).

EDIT: From what I understand now, all this stuff is equivalent to:

template<typenam _Tp>
struct __declval_protector
{
    const bool __stop = false;
};

template<typename _Tp>
typename add_rvalue_reference<_Tp>::type
mydeclval ()
{
    static_assert(__declval_protector<_Tp>::__stop, "declval() must not be used!");
}

But of course the compiler will issue that we do not return anything.

Mattia F.
  • 1,720
  • 11
  • 21
  • `__delegate` is a function. It's just like `int f();`, and the you say `f()`. – Kerrek SB Jun 15 '16 at 18:33
  • @vsoftco I have reopened the question as I am pretty sure it is not a duplicate. The question has a misleading title but it targets declval protector usage, not declval principles of work. – Edgar Rokjān Jun 03 '18 at 10:52
  • Does this answer your question? [How does std::declval() work?](https://stackoverflow.com/questions/28532781/how-does-stddeclvalt-work) – warrior_monk Dec 25 '21 at 06:10

1 Answers1

18

I don't understand why the static_assert is not called every time I call declval, since __stop is always false

Your premise is wrong. The static assert is indeed called every time you call declval. The trick is that you must never call declval. It must only be used in unevaluated contexts. That's why the static assertion is there.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • And what's the purpose of the return statement? – Mattia F. Jun 15 '16 at 18:37
  • 1
    @MattiaF.: To make the function well-formed and avoid warnings perhaps? Note that the function isn't defined, by the way. – Kerrek SB Jun 15 '16 at 18:39
  • I am surprised gcc actually has this implementation. I'd expect it to have declaration only. Are they trying to be nice to users? :) – SergeyA Jun 15 '16 at 18:40
  • Funny thing is that this template is ill-formed since it has no valid specialization. But it's okay since it occurs inside the implementation ;) – Brian Bi Jun 15 '16 at 18:47
  • @Brian Hmm, there can hypothetically be a specialization of `__declval_protector` later that has a true `__stop`, no? – T.C. Jun 15 '16 at 18:49
  • @T.C. Oh yeah, that could be the case... I just realized I'm not entirely sure how that rule is supposed to be interpreted. – Brian Bi Jun 15 '16 at 18:50
  • 2
    @T.C. It would be a lot simpler if we could just allow `static_assert(false, ...)` in these cases. – Barry Jun 15 '16 at 18:56
  • 5
    @Mattia F. If a static_assert isn't dependent on a template parameter, it fires whether the template is instantiated or not. – md5i Jun 15 '16 at 19:16
  • @T.C.: I think It's also UB if your program defines specializations that are not visible at the time of instantiation, isn't it? – Kerrek SB Jun 15 '16 at 21:33
  • @KerrekSB Time of instantiation or time of definition? Of course this triggers an error at instantiation time when there turns out to be no such specialization after all. – T.C. Jun 15 '16 at 21:35
  • @T.C.: Hm, that's true. I was trying to address the point of the template being ill-formed, but I'm not sure whether it really matters. – Kerrek SB Jun 15 '16 at 23:36