C++ Types Impossible to Name
While reading Wikipedia's page on decltype, I was curious about the statement,
Its [decltype's] primary intended use is in generic programming, where it is often difficult, or even impossible, to name types that depend on template parameters.
While I can understand the difficulty part of that statement, what is开发者_Go百科 an example where there is a need to name a type that cannot be named under C++03?
EDIT: My point is that since everything in C++ has a declaration of types. Why would there ever be a case where it is impossible to name a type? Furthermore, aren't trait classes designed to yield type informations? Could trait classes be an alternative to decltype
?
The wikipedia page you link has a perfect example:
int& foo(int& i);
float foo(float& f);
template <class T> auto transparent_forwarder(T& t) −> decltype(foo(t)) {
return foo(t);
}
Note that foo(int&)
returns int&
(a reference type) while foo(float&)
returns float
(a nonreference type). Without decltype
, it's impossible within the template to specify a type which represents "the return type of the function foo
which takes an argument t
of type T
".
In this example, it's not a particular concrete type which is impossible to express -- either int&
or float
are individually expressible -- but a higher level generic class of types.
EDIT: and to answer your comment to another answer, this example is inexpressible in C++03. You cannot have a function template which will wrap any function T1 foo(T2)
and match both argument and return type of the wrapped function.
There are types in C++0x (and in C++03, but less often) that cannot be named explicitly, such as the type decltype(f)
after the declaration auto f = [](int x) -> int {return x;};
. You would need to typedef
that decltype
result to something to get a name at all. Traits classes can be used for determining return types, but they are messy, and the user needs to duplicate all of their function overloads with traits class overloads; that is difficult to do correctly for cases such as functions applying (through implicit conversion of pointers) to all subclasses of a given base class.
As you pointed out, the type if it exist is known by the compiler, otherwise it wouldn't exist. However, it is not always readily or even accessible to the programmer in C++03.
N1607 mention the following in its conclusion:
In C++2003, it is not possible to express the return type of a function template in all cases. Furthermore, expressions involving calls to function templates commonly have very complicated types, which are practically impossible to write by hand
The question is how do we access this type as a programmer. This is not always a trivial process, often impracticable. It is increasingly complex when you have an expression for which you desire to know the result type. You would have to break it into pieces in order to figure the result types. It is not possible to simplify this process using templates (not without evaluating the expression anyhow). Breaking the expression will be error-prone, tedious and a nightmare to maintain. Think of this code:
x.g()[b.a(e)]->f();
With C++98/TR1, it is often infeasible to name types that depend on template parameters. Traits offers us so much information, but eventually decltype is a much cleaner solution to many problems. A lot of the information available to you when meta programming is only available because libraries, such as boost or loki, use several tricks hidden in the dark corners of the C++98 language.
Of course this is irrelevant to your question but I believe that it is worthy to mention that C++98 compilers already have mechanics to know these types. This is exactly what sizeof offers, except that it returns you a size. decltype reuse some of this functionality and solves these problems with greater elegance.
As for a different (academic) example:
struct Foo
{
struct
{
int x;
} bar;
};
template<typename T>
void
f(const T& t)
{
// C++03, How can I name the type of T::bar ?
// C++0x
// decltype(t.bar) cpy;
// Do stuff with our local cpy
}
int
main()
{
f(Foo());
}
精彩评论