9

I know:

  • typeof is a gcc extension and is not part of the C++ standard.

Questions:

  1. Is the word typeof deprecated in C++11? in other words, is it allowed to still use it as a gcc extension when using C++11?
  2. Is it correct to say that replacing every typeof with decltype yields the same behaviour of the code?
  3. Assume I have template<typename T> class wrapper. What is the best way to declare wrapper_some_field such that it is equivalent to: Wrapper<typeof(some_field)> wrapper_some_field
Hanna Khalil
  • 975
  • 1
  • 10
  • 28

2 Answers2

12

Is the word typeof deprecated in C++11? in other words, is it allowed to still use it as a gcc extension when using C++11?

It's not deprecated. It never existed as a keyword. gcc suggests that if you compile with -std=c++** that you instead use __typeof__.

Is it correct to say that replacing every typeof with decltype yields the same behaviour of the code?

No. For example, given:

int& foo();

decltype(foo()) is int& but __typeof__(foo()) is int.

Assume I have template<typename T> class wrapper. [...]

You could write wrapper<std::remove_reference_t<decltype(some_field)>> wrap{some_field}, but it'd be cleaner to write a construction function template:

template <class T> wrapper<T> make_wrapper(T const& val) { return {val}; }
auto wrap = make_wrapper(some_field);

Or, with forwarding:

template <class T>
wrapper<std::decay_t<T>> make_wrapper(T&& val) {
    return {std::forward<T>(val)};
}

Although in C++17 you wouldn't do this at all and would just use class template argument deduction:

template <class T> struct wrapper { T t; };
template <class T> wrapper(T) -> wrapper<T>;
auto wrap = wrapper{42}; // wrap is a wrapper<int>

And in C++20, you won't even need the deduction guide.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • 1
    Thank you. Could you please provide reference to gcc's advice? And What is this syntax {some_field}. And does the last one work to declare class field? – Hanna Khalil Jun 06 '16 at 15:26
  • 1
    That `make_wrapper` wastefully copies sometimes: a `make_X` should perfect forward in my opinion. – Yakk - Adam Nevraumont Jun 06 '16 at 15:28
  • @HannaKhalil Added. It's called list-initialization. And I don't know what you're asking. – Barry Jun 06 '16 at 15:32
  • @Yakk-AdamNevraumont "should perfect forward" in case of `make_wapper(T &&val)` only. – fiorentinoing Feb 08 '19 at 15:31
  • @fiorentinoing No, a `make_` function should perfect forward. If it is `make_wrapper( T const& )` it shouldn't follow the naming convention of C++ std `make_` functions which *do* perfect forward. – Yakk - Adam Nevraumont Feb 08 '19 at 15:34
  • @Yakk-AdamNevraumont I don't get the point about perfect forward an lvalue (const ref), it either copy too or just not work as you expected it to. – fiorentinoing Feb 08 '19 at 15:38
  • @fiorentinoing The signature of something to be perfect forwarded from `make_wrapper` shouldn't be `T const&`. It should be `T&&`, which can deduce `T` to be `X const&` or `X` for some type `X`, then inside the body it should be `std::forward(t)`. Regardless, my comments aren't aimed at you, they are aimed at @Barry, and comments are not a place for a discussion. – Yakk - Adam Nevraumont Feb 08 '19 at 15:48
  • I added a forwarding version of `make_wrapper`. – Barry Feb 08 '19 at 15:49
  • @Barry Sorry for the spam Barry; it was a throw away comment from 2 years ago. – Yakk - Adam Nevraumont Feb 08 '19 at 15:50
  • agreed (both saying same thing, thanks for sharing ideas) – fiorentinoing Feb 08 '19 at 16:01
  • 1
    @Yakk-AdamNevraumont No worries. Just because it's an old answer, doesn't mean it shouldn't be a good answer :-) – Barry Feb 08 '19 at 16:03
5
#define typeof(...) std::remove_reference_t<decltype(__VA_ARGS__)>;

However, if you want to create storage for a type T, the way to do it in C++11 is to use std::decay_t, or in some situations write your own extension that stores C-style arrays into a std::array.

Wrapper<std::decay_t<T>> wrapper_some_field;

if you want to pass Wrapper a type suitable for storing inside of it.

decay removes references, converts functions to pointers-to-functions, and arrays of T to pointers-to-T, and removes top-level const and volatile after that. These are operations similar to what happens when you pass things to a function as part of the "decay-to-pointer/value" operations.

The result is a type "suitable for storage". As noted, I'd prefer that a int[4] decay to a std::array<int,4> but you cannot have everything.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524