Difference between decltype and typeof? - c++

Two question regarding decltype and typeof:
Is there any difference between the decltype and typeof operators?
Does typeof become obsolete in C++11?

There is no typeof operator in c++. While it is true that such a functionality has been offered by most compilers for quite some time, it has always been a compiler specific language extension. Therefore comparing the behaviour of the two in general doesn't make sense, since the behaviour of typeof (if it even exists) is extremely platform dependent.
Since we now have a standard way of getting the type of a variable/expression, there is really no reason to rely on non portable extensions, so I would say it's pretty much obsolete.
Another thing to consider is that if the behaviour is of typeof isn't compatible with decltype for a given compiler it is possible that the typeof extension won't get much development to encompass new language features in the future (meaning it might simply not work with e.g. lambdas). I don't know whether or not that is currently the case, but it is a distinct possibility.

The difference between the two is that decltype always preserves references as part of the information, whereas typeof may not. So...
int a = 1;
int& ra = a;
typeof(a) b = 1; // int
typeof(ra) b2 = 1; // int
decltype(a) b3; // int
decltype(ra) b4 = a; // reference to int
The name typeof was the preferred choice (consistent with sizeof and alignof, and the name already used in extensions), but as you can see in the proposal N1478, concern around compatibility with existing implementations dropping references led them to giving it a distinct name.
"We use the operator name typeof when referring to the mechanism for querying a type of an expression in general. The decltype operator refers to the proposed variant of typeof. ... Some compiler vendors (EDG, Metrowerks, GCC) provide a typeof operator as an extension with reference-dropping semantics. As described in Section 4, this appears to be ideal for expressing the type of variables. On the other hand, the reference-dropping semantics fails to provide a mechanism for exactly expressing the return types of generic functions ... In this proposal, the semantics of the operator that provides information of the type of expressions reflects the declared type. Therefore, we propose the operator to be named decltype."
J. Jarvi, B. Stroustrup, D. Gregor, J. Siek: Decltype and auto. N1478/03-0061.
So it's incorrect to say that decltype completely obviated typeof (if you want reference dropping semantics, then the typeof extension in those compilers still has use), but rather, typeof was largely obviated by it plus auto, which does drop references and replaces uses where typeof was used for variable inference.
p.s. 2023-01-03 C23 (not C++) will evidently officially get typeof in N2927.

For legacy code, I have been using successfully the following:
#include <type_traits>
#define typeof(x) std::remove_reference<decltype((x))>::type

typeof has not been standardized, although it was implemented by several compiler vendors, e.g., GCC. It became obsolete with decltype.
A good explanation for the shortcomings of typeof can be found in this related answer.

Well, typeof is a non-standard GNU C extension that you can use in GNU C++ because GCC allows you to use features from other languages in another (not always though), so they really shouldn't be compared.
Of course other non-standard extensions may exist for other compilers, but GCC is definitely the most widely documented implementation.
To answer the question: it can't be obsolete if it was never a feature.
If you want to compare the merits of either method in C++ then there is semantically no difference unless you're dealing with references. You should use decltype because it is portable and standards conforming.

Related

How to determine arg type in c++

in gcc, I can use following code:
#define is_t(smth, type) ({int is_t_result; if (__builtin_types_compatible_p(__typeof__(smth), type)) {is_t_result = 1;}; is_t_result;})
but when I run it in googletest(c++), it raise
error: expected primary-expression before ‘__typeof__’
is there alternative to implement is_t in cpp?
This is a very complicated question, because there are many different ways to "detect types", depending on what it is you are trying to accomplish. There are basically two different categories of "type checking": compile-time and run-time. In terms of compile-time checking, it is very common to use "duck-typing" with C++ templates (it works if it satisfies the implicit requirements); however, there are some cases where this is not sufficient, and <type_traits> and static_assert provide ways to enforce requirements more explicitly, while decltype allows one to refer to the type that would be returned by an expression. Type conversion at runtime is less common in C++ (usually it is done implicitly through "dynamic dispatch", a.k.a. virtual functions); however, in terms of explicitly checking the runtime type of an object, there is the dynamic_cast<T> mechanism.
Long-story short, though, your is_t() macro is probably best replaced by the builtin mechanisms for type-detection in C++. If you are using older versions of C++, Boost provides widely compatible equivalents that work across many C++ compilers and both C++98 and C++11. Doing so will make it much clearer what you mean by the variable being of that type. (E.g. is it declared to be exactly of that type, does it have that runtime type, is it declared to be of a type that is assignable to the other type).

Why cannot C type-generic expressions be compatible with C++?

I seem to recall hearing vague comments from a few reliable sources (i.e. committee members speaking in non-official channels) that C type-generic expressions will not be added to C++ because they cannot be.
As far as I can tell, type-generic expressions are very limited compared to C++ templates and overloading, but there is no potential for interaction that would need to be defined as a special case.
A type-generic expression consists of a controlling expression, and a series of "associations" between types and subexpressions. A subexpression is chosen based on the static type of the controlling expression and the types listed for the subexpressions, and it is substituted in place of the TGE. Matching is based on the C concept of type compatibility, which as far as I can tell is equivalent to C++ identity of types with extern linkage under the one-definition rule (ODR).
It would be nice if a derived class controlling expression would select a base class association in C++, but since C doesn't have inheritance, such nicety isn't needed for cross-compatibility. Is this considered to be a stumbling block anyway?
Edit: As for more specific details, C11 already provides for preserving the value category (lvalue-ness) of the chosen subexpression, and seems to require that the TGE is a constant expression (of whatever category) as long as all its operands are, including the controlling expression. This is probably a C language defect. In any case, C++14 defines constant expressions in terms of what may be potentially evaluated, and the TGE spec already says that non-chosen subexpressions are unevaluated.
The point is that the TGE principle of operation seems simple enough to be transplanted without ever causing trouble later.
As for why C++ TGE's would be useful, aside from maximizing the intersection of C and C++, they could be used to essentially implement static_if, sans the highly controversial conditional declaration feature. I'm not a proponent of static_if, but "there is that."
template< typename t >
void f( t q ) {
auto is_big = _Generic( std::integral_constant< bool, sizeof q >= 4 >(),
std::true_type: std::string( "whatta whopper" ),
std::false_type: "no big deal"
);
auto message = _Generic( t, double: "double", int: 42, default: t );
std::cout << message << " " << is_big << '\n';
}
"Cannot be" is perhaps too strong. "Uncertain whether it's possible" is more likely.
If this feature were to be added to C++, it should be fully specified including all interactions with existing C++ features, many of which were not designed with _Generic in mind. E.g. typeid doesn't exist in C, but should work in C++. Can you use a _Generic expression as a constexpr? As a template parameter? Is it an lvalue ? Can you take its address and assign that to a function pointer, and get overload resolution? Can you do template argument deduction? Can you use it with auto? Etc.
Another complication is that the primary usecase for _Generic is for macro's, which don't play nice with C++ namespaces. The acos example from tgmath is a clear example. C++ already banned C's standard macro's and required them to be functions, but that won't work with tgmath.h.

Why isn't std::initializer_list a language built-in?

Why isn't std::initializer_list a core-language built-in?
It seems to me that it's quite an important feature of C++11 and yet it doesn't have its own reserved keyword (or something alike).
Instead, initializer_list it's just a template class from the standard library that has a special, implicit mapping from the new braced-init-list {...} syntax that's handled by the compiler.
At first thought, this solution is quite hacky.
Is this the way new additions to the C++ language will be now implemented: by implicit roles of some template classes and not by the core language?
Please consider these examples:
widget<int> w = {1,2,3}; //this is how we want to use a class
why was a new class chosen:
widget( std::initializer_list<T> init )
instead of using something similar to any of these ideas:
widget( T[] init, int length ) // (1)
widget( T... init ) // (2)
widget( std::vector<T> init ) // (3)
a classic array, you could probably add const here and there
three dots already exist in the language (var-args, now variadic templates), why not re-use the syntax (and make it feel built-in)
just an existing container, could add const and &
All of them are already a part of the language. I only wrote my 3 first ideas, I am sure that there are many other approaches.
There were already examples of "core" language features that returned types defined in the std namespace. typeid returns std::type_info and (stretching a point perhaps) sizeof returns std::size_t.
In the former case, you already need to include a standard header in order to use this so-called "core language" feature.
Now, for initializer lists it happens that no keyword is needed to generate the object, the syntax is context-sensitive curly braces. Aside from that it's the same as type_info. Personally I don't think the absence of a keyword makes it "more hacky". Slightly more surprising, perhaps, but remember that the objective was to allow the same braced-initializer syntax that was already allowed for aggregates.
So yes, you can probably expect more of this design principle in future:
if more occasions arise where it is possible to introduce new features without new keywords then the committee will take them.
if new features require complex types, then those types will be placed in std rather than as builtins.
Hence:
if a new feature requires a complex type and can be introduced without new keywords then you'll get what you have here, which is "core language" syntax with no new keywords and that uses library types from std.
What it comes down to, I think, is that there is no absolute division in C++ between the "core language" and the standard libraries. They're different chapters in the standard but each references the other, and it has always been so.
There is another approach in C++11, which is that lambdas introduce objects that have anonymous types generated by the compiler. Because they have no names they aren't in a namespace at all, certainly not in std. That's not a suitable approach for initializer lists, though, because you use the type name when you write the constructor that accepts one.
The C++ Standard Committee seems to prefer not to add new keywords, probably because that increases the risk of breaking existing code (legacy code could use that keyword as the name of a variable, a class, or whatever else).
Moreover, it seems to me that defining std::initializer_list as a templated container is quite an elegant choice: if it was a keyword, how would you access its underlying type? How would you iterate through it? You would need a bunch of new operators as well, and that would just force you to remember more names and more keywords to do the same things you can do with standard containers.
Treating an std::initializer_list as any other container gives you the opportunity of writing generic code that works with any of those things.
UPDATE:
Then why introduce a new type, instead of using some combination of existing? (from the comments)
To begin with, all others containers have methods for adding, removing, and emplacing elements, which are not desirable for a compiler-generated collection. The only exception is std::array<>, which wraps a fixed-size C-style array and would therefore remain the only reasonable candidate.
However, as Nicol Bolas correctly points out in the comments, another, fundamental difference between std::initializer_list and all other standard containers (including std::array<>) is that the latter ones have value semantics, while std::initializer_list has reference semantics. Copying an std::initializer_list, for instance, won't cause a copy of the elements it contains.
Moreover (once again, courtesy of Nicol Bolas), having a special container for brace-initialization lists allows overloading on the way the user is performing initialization.
This is nothing new. For example, for (i : some_container) relies on existence of specific methods or standalone functions in some_container class. C# even relies even more on its .NET libraries. Actually, I think, that this is quite an elegant solution, because you can make your classes compatible with some language structures without complicating language specification.
This is indeed nothing new and how many have pointed out, this practice was there in C++ and is there, say, in C#.
Andrei Alexandrescu has mentioned a good point about this though: You may think of it as a part of imaginary "core" namespace, then it'll make more sense.
So, it's actually something like: core::initializer_list, core::size_t, core::begin(), core::end() and so on. This is just an unfortunate coincidence that std namespace has some core language constructs inside it.
Not only can it work completely in the standard library. Inclusion into the standard library does not mean that the compiler can not play clever tricks.
While it may not be able to in all cases, it may very well say: this type is well known, or a simple type, lets ignore the initializer_list and just have a memory image of what the initialized value should be.
In other words int i {5}; can be equivalent to int i(5); or int i=5; or even intwrapper iw {5}; Where intwrapper is a simple wrapper class over an int with a trivial constructor taking an initializer_list
It's not part of the core language because it can be implemented entirely in the library, just line operator new and operator delete. What advantage would there be in making compilers more complicated to build it in?

Why is there a sizeof... operator in C++0x?

I saw that #GMan implemented a version of sizeof... for variadic templates which (as far as I can tell) is equivalent to the built in sizeof.... Doesn't this go against the second design principle: prefer libraries to language extensions?
From Variadic Templates (Revision 3)
(N2080=06-0150), page 6:
Although not strictly necessary (we can implement count without this feature), checking the length of a parameter pack is a common operation that deserves a simple syntax. Moreover, this operation may become necessary for type-checking reasons when variadic templates are combined with concepts; see Section 3.3.
(Section 3.3 talks about concepts which is irrelevant now.)
sizeof... is just sugar, I think.
sizeof is indeed core to the language as is ..., and although a countof function could exist we already have sizeof and ... reserved so we might as well make it convenient to get the count that way.
Contrarily, if sizeof and ... weren't reserved, the idea of adding such a thing would have probably failed because new keywords tend to be frowned upon. (The less the better.)

C++0x, Compiler hooks and hard coded languages features

I'm a little curious about some of the new features of C++0x. In particular range-based for loops and initializer lists. Both features require a user-defined class in order to function correctly.
I came accross this post, and while the top-answer was helpful. I don't know if it's entirely correct (I'm probably just completely misunderstanding, see 3rd comment on first answer). According to the current specifications for initializer lists, the header defines one type:
template<class E> class initializer_list {
public:
initializer_list();
size_t size() const; // number of elements
const E* begin() const; // first element
const E* end() const; // one past the last element
};
You can see this in the specifications, just Ctrl + F 'class initializer_list'.
In order for = {1,2,3} to be implicitly casted into the initializer_list class, the compiler HAS to have some knowledge of the relationship between {} and initializer_list. There is no constructor that receives anything, so the initializer_list as far as I can tell is a wrapper that gets bound to whatever the compiler is actually generating.
It's the same with the for( : ) loop, which also requires a user-defined type to work (though according to the specs, updated to not require any code for arrays and initializer lists. But initializer lists require <initializer_list>, so it's a user-defined code requirement by proxy).
Am I misunderstanding completely how this works here? I'm not wrong in thinking that these new features do infact rely extremely heavily on user code. It feels as if the features are half-baked, and instead of building the entire feature into the compiler, it's being half-done by the compiler and half done in includes. What's the reason for this?
Edit: I typed 'rely heavily on compiler code', and not 'rely heavily on user code'. Which I think completely threw off my question. My confusion isn't about new features being built into the compiler, it's things that are built into the compiler that rely on user code.
I'm not wrong in thinking that these new features do infact rely extremely heavily on compiler code
They do rely extremely on the compiler. Whether you need to include a header or not, the fact is that in both cases, the syntax would be a parsing error with today compilers. The for (:) does not quite fit into todays standard, where the only allowed construct is for(;;)
It feels as if the features are half-baked, and instead of building the entire feature into the compiler, it's being half-done by the compiler and half done in includes. What's the reason for this?
The support must be implemented in the compiler, but you are required to include a system's header for it to work. This can serve a couple of purposes, in the case of initialization lists, it brings the type (interface to the compiler support) into scope for the user so that you can have a way of using it (think how va_args are in C). In the case of the range-based for (which is just syntactic sugar) you need to bring Range into scope so that the compiler can perform it's magic. Note that the standard defines for ( for-range-declaration : expression ) statement as equivalent to ([6.5.4]/1 in the draft):
{
auto && __range = ( expression );
for ( auto __begin = std::Range<_RangeT>::begin(__range),
__end = std::Range<_RangeT>::end(__range);
__begin != __end;
++__begin ) {
for-range-declaration = *__begin;
statement
}
}
If you want to use it only on arrays and STL containers that could be implemented without the Range concept (not in the C++0x sense), but if you want to extend the syntax into user defined classes (your own containers) the compiler can easily depend upon the existing Range template (with your own possible specialization). The mechanism of depending upon a template being defined is equivalent to requiring a static interface on the container.
Most other languages have gone in the direction of requiring a regular interface (say Container,...) and using runtime polymorphism on that. If that was to be done in C++, the whole STL would have to go through a major refactoring as STL containers do not share a common base or interface, and they are not prepared to be used polimorphically.
If any, the current standard will not be underbaked by the time it goes out.
It's just syntax sugar. The compiler will expand the given syntactic constructs into equivalent C++ expressions that reference the standard types / symbol names directly.
This isn't the only strong coupling that modern C++ compilers have between their language and the "outside world". For example, extern "C" is a bit of a language hack to accommodate C's linking model. Language-oriented ways of declaring thread-local storage implicitly depend on lots of RTL hackery to work.
Or look at C. How do you access arguments passed via ...? You need to rely on the standard library; but that uses magic that has a very hard dependency on how exactly the C compiler lays out stack frames.
UPDATE:
If anything, the approach C++ has taken here is more in the spirit of C++ than the alternative - which would be to add an intrinsic collection or range type, baked in to the language. Instead, it's being done via a vendor-defined range type. I really don't see it as much different to variadic arguments, which are similarly useless without the vendor-defined accessor macros.