Determining if ::std::numeric_limits<T> is safe to instantiate - c++

The class template ::std::numeric_limits<T> may only be instantiated for types T, which can be the return value of functions, since it always defines member functions like static constexpr T min() noexcept { return T(); } (see http://www.cplusplus.com/reference/limits/numeric_limits/ for more information of the non-specialised versions in c++03 or c++11).
If T is i.e. int[2] the instantiation will immediately lead to a compile time error, since int[2] cannot be the return value of a function.
Wrapping ::std::numeric_limits with a safe version is easy - if a way to determine if it is safe to instantiate ::std::numeric_limits is known. This is necessary, since the problematic functions should be accessible if possible.
The obvious (and obviously wrong) way of testing ::std::numeric_limits<T>::is_specialised does not work since it requires instantiation of the problematic class template.
Is there a way to test for safety of instantiation, preferably without enumerating all known bad types? Maybe even a general technique to determine if any class template instantiation is safe?

Concerning the type trait that decides whether a type can be returned for a function, here is how I would go about it:
#include <type_traits>
template<typename T, typename = void>
struct can_be_returned_from_function : std::false_type { };
template<typename T>
struct can_be_returned_from_function<T,
typename std::enable_if<!std::is_abstract<T>::value,
decltype(std::declval<T()>(), (void)0)>::type>
: std::true_type { };
On the other hand, as suggested by Tom Knapen in the comments, you may want to use the std::is_arithmetic standard type trait to determine whether you can specialize numeric_limits for a certain type.
Per paragraph 18.3.2.1/2 of the C++11 Standard on the numeric_limits class template, in fact:
Specializations shall be provided for each arithmetic type, both floating point and integer, including bool.
The member is_specialized shall be true for all such specializations of numeric_limits.

C++11 solutions
Since T only appears as the return type of static member functions in the declarations of the unspecialised ::std::numeric_limits<T> (see C++03 18.2.1.1 and C++11 18.3.2.3), it is enough for this specific problem to ensure that doing so is declaration-safe.
The reason this leads to a compile time error is, that the use of a template-argument may not give rise to an ill-formed construct in the instantiation of the template specialization (C++03 14.3/6, C++11 14.3/6).
For C++11 enabled projects, Andy Prowl's can_be_returned_from_function solution works in all relevant cases: http://ideone.com/SZB2bj , but it is not easily portable to a C++03 environment. It causes an error in when instantiated with an incomplete type ( http://ideone.com/k4Y25z ). The proposed solution will accept incomplete classes instead of causing an error. The current Microsoft compiler (msvc 1700 / VS2012) seems to dislike this solution and fail to compile.
Jonathan Wakely proposed a solution that works by utilizing std::is_convertible<T, T> to determine if T can be the return value of a function. This also eliminates incomplete classes, and is easy to show correct (it is defined in C++11 to do exactly what we want). Execution shows that all cases (arrays, arrays of undefined length, functions, abstract classes) which are known to be problematic are correctly recognized. As a bonus, it also correctly recognizes incomplete classes, which are not allowed as parameters to numeric_limits by the standards (see below), although they seem to cause no problems in practice, as long as no problematic functions are actually called. Test execution: http://ideone.com/zolXpp . Some current compilers (icc 1310 and msvc 1700, which is VS2012's compiler) generate incorrect results with this method.
Tom Knapen's is_arithmetic solution is a very concise C++11 solution, but requires the implementer of a type that specialises numeric_limits to also specialise is_arithmetic. Alternatively, a type that in its base case inherits from is_arithmetic (this type might be called numeric_limits_is_specialised) might be specialised in those cases, since specialising is_abstract might not be semantically correct (e.g. a type that does not specify all basic arithmetic operators, but still is a valid integer-like type).
This whitelisting approach ensures that even incomplete types are handled correctly, unless someone maliciously tries to force compilation errors.
Caveat
As shown by the mixed results, C++11 support remains spotty, even with current compilers, so your mileage with these solutions may vary. A C++03 solution will benefit from more consistent results and the ability to be used in projects that do not wish to switch to C++11.
Towards a robust C++03 solution
Paragraph C++11 8.3.5/8 lists the restrictions for return values:
If the type of a parameter includes a type of the form "pointer to array of unknown bound of T" or "reference to array of unknown bound of T", the program is ill-formed. Functions shall not have a return type of type array or function, although they may have a return type of type pointer or reference to such things. There shall be no arrays of functions, although there can be arrays of pointers to functions.
and goes on in paragraph C++11 8.3.5/9:
Types shall not be defined in return or parameter types. The type of a parameter or the return type for a function definition shall not be an incomplete class type (possibly cv-qualified) unless the function definition is nested within the member-specification for that class (including definitions in nested classes defined within the class).
Which is pretty much the same as paragraph C++03 8.3.5/6:
If the type of a parameter includes a type of the form "pointer to array of unknown bound of T" or "reference to array of unknown bound of T", the program is ill-formed. Functions shall not have a return type of type array or function, although they may have a return type of type pointer or reference to such things. There shall be no arrays of functions, although there can be arrays of pointers to functions. Types shall not
be defined in return or parameter types. The type of a parameter or the return type for a function definition shall not be an incomplete class type (possibly cv-qualified) unless the function definition is nested within the member-specification for that class (including definitions in nested classes defined within the class).
Another kind of problematic types is mentioned identically in C++11 10.4/3 and C++03 10.4/3:
An abstract class shall not be used as a parameter type, as a function return type, or as the type of an explicit conversion. [...]
The problematic functions are not nested within an incomplete class type (except of ::std::numeric_limits<T>, which cannot be their T), so we have four kinds of problematic values of T: Arrays, functions, incomplete class types and abstract class types.
Array Types
template<typename T> struct is_array
{ static const bool value = false; };
template<typename T> struct is_array<T[]>
{ static const bool value = true; };
template<typename T, size_t n> struct is_array<T[n]>
{ static const bool value = true; };
detects the simple case of T being an array type.
Incomplete Class Types
Incomplete class types interestingly do not lead to a compilation error just from instantiation, which means either the tested implementations are more forgiving than the standard, or I am missing something.
C++03 example: http://ideone.com/qZUa1N
C++11 example: http://ideone.com/MkA0Gr
Since I cannot come up with a proper way to detect incomplete types, and even the standard specifies (C++03 17.4.3.6/2 item 5)
In particular, the effects are undefined in the following cases: [...] if an incomplete type (3.9) is used as a template argument when instantiating a template component.
Adding only the following special allowance in C++11 (17.6.4.8/2):
[...] unless specifically allowed for that component
it seems safe to assume that anybody passing incomplete types as template parameters are on their own.
A complete list of the cases where C++11 allows incomplete type parameters is quite short:
declval
unique_ptr
default_delete (C++11 20.7.1.1.1/1: "The class template default_delete serves as the default deleter (destruction policy) for the class template unique_ptr."
shared_ptr
weak_ptr
enable_shared_from_this
Abstract Class & Function Types
Detecting functions is a bit more work than in C++11, since we do not have variadic templates in C++03. However, the above quotes on functions already contain the hint we need; functions may not be elements of arrays.
Paragraph C++11 8.3.4\1 contains the sentence
T is called the array element type; this type shall not be a reference type, the (possibly cv qualified) type void, a function type or an abstract class type.
which is also verbatim in paragraph C++03 8.3.4\1 and will allow us to test if a type is a function type. Detecting (cv) void and reference types is simple:
template<typename T> struct is_reference
{ static const bool value = false; };
template<typename T> struct is_reference<T&>
{ static const bool value = true; };
template<typename T> struct is_void
{ static const bool value = false; };
template<> struct is_void<void>
{ static const bool value = true; };
template<> struct is_void<void const>
{ static const bool value = true; };
template<> struct is_void<void volatile>
{ static const bool value = true; };
template<> struct is_void<void const volatile>
{ static const bool value = true; };
Using this, it is simple to write a meta function for abstract class types and functions:
template<typename T>
class is_abstract_class_or_function
{
typedef char (&Two)[2];
template<typename U> static char test(U(*)[1]);
template<typename U> static Two test(...);
public:
static const bool value =
!is_reference<T>::value &&
!is_void<T>::value &&
(sizeof(test<T>(0)) == sizeof(Two));
};
Note that the following meta function may be used to distinguish between the two, should one wish to make a distinct is_function and is_abstract_class
template<typename T>
class is_class
{
typedef char (&Two)[2];
template<typename U> static char test(int (U::*));
template<typename U> static Two test(...);
public:
static const bool value = (sizeof(test<T>(0)) == sizeof(char));
};
Solution
Combining all of the previous work, we can construct the is_returnable meta function:
template<typename T> struct is_returnable
{ static const bool value = !is_array<T>::value && !is_abstract_class_or_function<T>::value; };
Execution for C++03 (gcc 4.3.2): http://ideone.com/thuqXY
Execution for C++03 (gcc 4.7.2): http://ideone.com/OR4Swf
Execution for C++11 (gcc 4.7.2): http://ideone.com/zIu7GJ
As expected, all test cases except for the incomplete class yield the correct answer.
In addition to the above test runs, this version is tested (with the exact same test program) to yield the same results w/o warnings or errors on:
MSVC 1700 (VS2012 with and w/o XP profile), 1600 (VS2010), 1500 (VS2008)
ICC Win 1310
GCC (C++03 and C++11/C++0x mode) 4.4.7, 4.6.4, 4.8.0 and a 4.9 snapshot
Restrictions for either case
Note that, while this approach in either version works for any numeric_limits implementation that does not extend upon the implementation shown in the standard, it is by no means a solution to the general problem, and in fact may theoretically lead to problems with weird but standard compliant implementations (e.g. ones which add private members).
Incomplete classes remain a problem, but it seems silly to require higher robustness goals than the standard library itself.

std::is_convertible<T, T>::value will tell you if a type can be returned from a function.
is_convertible<T1, T2> is defined in terms of a function returning a T2 converted from an expression of type T1.
#include <limits>
#include <type_traits>
struct Incomplete;
struct Abstract { virtual void f() = 0; };
template<typename T>
using is_numeric_limits_safe = std::is_convertible<T, T>;
int main()
{
static_assert(!is_numeric_limits_safe<Incomplete>::value, "Incomplete");
static_assert(!is_numeric_limits_safe<Abstract>::value, "Abstract");
static_assert(!is_numeric_limits_safe<int[2]>::value, "int[2]");
}
This might not be exactly what you want, because it is safe to instantiate std::numeric_limits<Incomplete> as long as you don't call any of the functions that return by value. It's not possible to instantiate std::numeric_limits<int[2]> though.
Here's a better test (using SFINAE) which gives is_numeric_limits_safe<Incomplete>::value==true
template<typename T>
class is_numeric_limits_unsafe
{
struct mu { };
template<typename U>
static U test(int);
template<typename U>
static mu test(...);
public:
typedef std::is_same<decltype(test<T>(0)), mu> type;
};
template<typename T>
struct is_numeric_limits_safe
: std::integral_constant<bool, !is_numeric_limits_unsafe<T>::type::value>
{ };

Related

Type trait for aggregate initializability in the standard library?

The C++ standard library has std::is_constructible<Class, T...> to check if a class can be constructed from the given types as arguments.
For example, if I have a class MyClass which has a constructor MyClass(int, char), then std::is_constructible<MyClass, int, char>::value will be true.
Is there a similar standard library type trait that will check that aggregate initialization works, i.e. MyClass{int, char} is well-formed and returns a MyClass?
My use case:
I want to write a function template that converts a std::tuple to a (usually POD) class using aggregate initialization, something with the following signature:
template <typename Class, typename... T>
inline Class to_struct(std::tuple<T...>&& tp);
In order to prevent users from using this function with an invalid Class, I could write a static_assert inside this function to check if the given tp parameter has types that are convertible to the members of Class. It seems a type trait like is_aggregate_initializable<Class, T...> would come in handy.
I could roll my own implementation of this trait, but just for information, is there such a trait in the standard library that I've overlooked, or one that is soon to become part of the standard library?
From the discussion in the comments and browsing the C++ reference, it seems like there is a standard library type trait for neither aggregate initializability nor list initializability, at least up to C++17.
It was highlighted in the comments that there was a distinction between list initializability in general (Class{arg1, arg2, ...}) and aggregate initializability.
List initializability (specifically direct list initializability) is easier to write a type trait for because this trait is solely dependent on the validity of a certain syntax. For my use case of testing if a struct can be constructed from the elements of a tuple, direct list initializability seems to be more appropriate.
A possible way to implement this trait (with appropriate SFINAE) is as follows:
namespace detail {
template <typename Struct, typename = void, typename... T>
struct is_direct_list_initializable_impl : std::false_type {};
template <typename Struct, typename... T>
struct is_direct_list_initializable_impl<Struct, std::void_t<decltype(Struct{ std::declval<T>()... })>, T...> : std::true_type {};
}
template <typename Struct, typename... T>
using is_direct_list_initializable = detail::is_direct_list_initializable_impl<Struct, void, T...>;
template<typename Struct, typename... T>
constexpr bool is_direct_list_initializable_v = is_direct_list_initializable<Struct, T...>::value;
Then we can test direct list initializability by doing is_direct_list_initializable_v<Class, T...>.
This also works with move semantics and perfect forwarding, because std::declval honors perfect forwarding rules.
Aggregate initializability is less straightforward, but there is a solution that covers most cases. Aggregate initialization requires the type being initialized to be an aggregate (see explanation on the C++ reference on aggregate initialization), and we have a C++17 trait std::is_aggregate that checks if a type is an aggregate.
However, it doesn't mean that just because the type is an aggregate the usual direct list initialization would be invalid. Normal list initialization that matches constructors is still allowed. For example, the following compiles:
struct point {
int x,y;
};
int main() {
point e1{8}; // aggregate initialization :)
point e2{e1}; // this is not aggregate initialization!
}
To disallow this kind of list initialization, we can utilize the fact that aggregates cannot have custom (i.e. user-provided) constructors, so non-aggregate initialization must have only one parameter and Class{arg} will satisfy std::is_same_v<Class, std::decay_t<decltype(arg)>>.
Luckily, we can't have a member variable of the same type as its enclosing class, so the following is invalid:
struct point {
point x;
};
There is a caveat to this: reference types to the same object are allowed because member references can be incomplete types (GCC, Clang, and MSVC all accepts this without any warnings):
struct point {
point& x;
};
While unusual, this code is valid by the standard. I have no solution to detect this case and determine that point is aggregate initializable with an object of type point&.
Ignoring the caveat above (it is rare to need to use such a type), we can devise a solution that will work:
template <typename Struct, typename... T>
using is_aggregate_initializable = std::conjunction<std::is_aggregate<Struct>, is_direct_list_initializable<Struct, T...>, std::negation<std::conjunction<std::bool_constant<sizeof...(T) == 1>, std::is_same<std::decay_t<std::tuple_element_t<0, std::tuple<T...>>>, Struct>>>>;
template<typename Struct, typename... T>
constexpr bool is_aggregate_initializable_v = is_aggregate_initializable<Struct, T...>::value;
It doesn't look very nice, but does function as expected.

In C++, can I declare a template struct with a template parameter unused in the definition?

Recently I'm reading the source code from spirit-v2-json, and I have been confused with the following code:
template <typename Tag> struct Literal
{
bool operator==(Literal const&) const { return true; }
bool operator< (Literal const&) const { return false; }
};
typedef Literal<struct tag_undefined> Undefined;
typedef Literal<struct tag_null> Null;
Question 1: What's the meaning of the tag parameter in the template of Literal? It is unused.
Question 2: The struct tag_undefined and struct tag_null haven't been defined even declared, why can we use them as template parameters?
The purpose of the tag parameter is to differentiate between different types. There is no requirement for them to display any difference in functionality, but they need to be distinct classes. As this differentiation is the only purpose of the tag parameter and as it isn't used in any way in the template class itself, it is OK to use incomplete in-situ types directly in the typedef.
Why would you want to do this? In the above use case the code uses this template to define two distinct types, Undefined and Null. They could have just as easily created those types directly, using struct Null and struct Undefined, but then they would have had to define the operators operator= and operator< separately, which was probably considered a waste. Using a type tag in this way achieves the same effect with template code re-use.
If you look later on in the code the two types are actually passed as parameters to boost::variant, which is a "multi-type, single value" methodology to represent values in a variable type. Here the code wants to have the concept of Undefined and Null as distinct types in this multi-type system (I guess to represent undefined or null json objects).
UPDATE:
As per OP request, here is some code to demonstrate where incomplete types can and can not be used:
struct incomplete_struct;
struct complete_struct{};
template<typename tag>
struct some_templ
{};
template<typename tag>
struct some_other_templ
{
tag member;
};
int main()
{
some_templ<incomplete_struct> a; //OK - incomplete template param type but not used in class so not instantiated
some_templ<struct inline_incomplete> b; //OK - as above
some_other_templ<complete_struct> c; //OK - complete_struct is complete type
some_other_templ<incomplete_struct> d; //Compile error - incomplete type, and used in template - thus instantiation of incomplete_struct is required but impossible
return 0;
}
It seems that the template parameter is left unused, and is used only to differentiate between the type.
Yes, you can use undefined types as template parameters as long they're not used. Templates are a bit like a find&replace supported by the compiler, and since the template parameter is not used, it is not pasted anywhere in the code.

How does this implementation of std::is_class work?

I'm trying to understand the implementation of std::is_class. I've copied some possible implementations and compiled them, hoping to figure out how they work. That done, I find that all the computations are done during compilation (as I should have figured out sooner, looking back), so gdb can give me no more detail on what exactly is going on.
The implementation I'm struggling to understand is this one:
template<class T, T v>
struct integral_constant{
static constexpr T value = v;
typedef T value_type;
typedef integral_constant type;
constexpr operator value_type() const noexcept {
return value;
}
};
namespace detail {
template <class T> char test(int T::*); //this line
struct two{
char c[2];
};
template <class T> two test(...); //this line
}
//Not concerned about the is_union<T> implementation right now
template <class T>
struct is_class : std::integral_constant<bool, sizeof(detail::test<T>(0))==1
&& !std::is_union<T>::value> {};
I'm having trouble with the two commented lines. This first line:
template<class T> char test(int T::*);
What does the T::* mean? Also, is this not a function declaration? It looks like one, yet this compiles without defining a function body.
The second line I want to understand is:
template<class T> two test(...);
Once again, is this not a function declaration with no body ever defined? Also what does the ellipsis mean in this context? I thought an ellipsis as a function argument required one defined argument before the ...?
I would like to understand what this code is doing. I know I can just use the already implemented functions from the standard library, but I want to understand how they work.
References:
std::is_class
std::integral_constant
What you are looking at is some programming technologie called "SFINAE" which stands for "Substitution failure is not an error". The basic idea is this:
namespace detail {
template <class T> char test(int T::*); //this line
struct two{
char c[2];
};
template <class T> two test(...); //this line
}
This namespace provides 2 overloads for test(). Both are templates, resolved at compile time. The first one takes a int T::* as argument. It is called a Member-Pointer and is a pointer to an int, but to an int thats a member of the class T. This is only a valid expression, if T is a class.
The second one is taking any number of arguments, which is valid in any case.
So how is it used?
sizeof(detail::test<T>(0))==1
Ok, we pass the function a 0 - this can be a pointer and especially a member-pointer - no information gained which overload to use from this.
So if T is a class, then we could use both the T::* and the ... overload here - and since the T::* overload is the more specific one here, it is used.
But if T is not a class, then we cant have something like T::* and the overload is ill-formed. But its a failure that happened during template-parameter substitution. And since "substitution failures are not an error" the compiler will silently ignore this overload.
Afterwards is the sizeof() applied. Noticed the different return types? So depending on T the compiler chooses the right overload and therefore the right return type, resulting in a size of either sizeof(char) or sizeof(char[2]).
And finally, since we only use the size of this function and never actually call it, we dont need an implementation.
Part of what is confusing you, which isn't explained by the other answers so far, is that the test functions are never actually called. The fact they have no definitions doesn't matter if you don't call them. As you realised, the whole thing happens at compile time, without running any code.
The expression sizeof(detail::test<T>(0)) uses the sizeof operator on a function call expression. The operand of sizeof is an unevaluated context, which means that the compiler doesn't actually execute that code (i.e. evaluate it to determine the result). It isn't necessary to call that function in order to know the sizeof what the result would be if you called it. To know the size of the result the compiler only needs to see the declarations of the various test functions (to know their return types) and then to perform overload resolution to see which one would be called, and so to find what the sizeof the result would be.
The rest of the puzzle is that the unevaluated function call detail::test<T>(0) determines whether T can be used to form a pointer-to-member type int T::*, which is only possible if T is a class type (because non-classes can't have members, and so can't have pointers to their members). If T is a class then the first test overload can be called, otherwise the second overload gets called. The second overload uses a printf-style ... parameter list, meaning it accepts anything, but is also considered a worse match than any other viable function (otherwise functions using ... would be too "greedy" and get called all the time, even if there's a more specific function t hat matches the arguments exactly). In this code the ... function is a fallback for "if nothing else matches, call this function", so if T isn't a class type the fallback is used.
It doesn't matter if the class type really has a member variable of type int, it is valid to form the type int T::* anyway for any class (you just couldn't make that pointer-to-member refer to any member if the type doesn't have an int member).
The std::is_class type trait is expressed through a compiler intrinsic (called __is_class on most popular compilers), and it cannot be implemented in "normal" C++.
Those manual C++ implementations of std::is_class can be used in educational purposes, but not in a real production code. Otherwise bad things might happen with forward-declared types (for which std::is_class should work correctly as well).
Here's an example that can be reproduced on any msvc x64 compiler.
Suppose I have written my own implementation of is_class:
namespace detail
{
template<typename T>
constexpr char test_my_bad_is_class_call(int T::*) { return {}; }
struct two { char _[2]; };
template<typename T>
constexpr two test_my_bad_is_class_call(...) { return {}; }
}
template<typename T>
struct my_bad_is_class
: std::bool_constant<sizeof(detail::test_my_bad_is_class_call<T>(nullptr)) == 1>
{
};
Let's try it:
class Test
{
};
static_assert(my_bad_is_class<Test>::value == true);
static_assert(my_bad_is_class<const Test>::value == true);
static_assert(my_bad_is_class<Test&>::value == false);
static_assert(my_bad_is_class<Test*>::value == false);
static_assert(my_bad_is_class<int>::value == false);
static_assert(my_bad_is_class<void>::value == false);
As long as the type T is fully defined by the moment my_bad_is_class is applied to it for the first time, everything will be okay. And the size of its member function pointer will remain what it should be:
// 8 is the default for such simple classes on msvc x64
static_assert(sizeof(void(Test::*)()) == 8);
However, things become quite "interesting" if we use our custom type trait with a forward-declared (and not yet defined) type:
class ProblemTest;
The following line implicitly requests the type int ProblemTest::* for a forward-declared class, definition of which cannot be seen by the compiler right now.
static_assert(my_bad_is_class<ProblemTest>::value == true);
This compiles, but, unexpectedly, breaks the size of a member function pointer.
It seems like the compiler attempts to "instantiate" (similarly to how templates are instantiated) the size of a pointer to ProblemTest's member function in the same moment that we request the type int ProblemTest::* within our my_bad_is_class implementation. And, currently, the compiler cannot know what it should be, thus it has no choice but to assume the largest possible size.
class ProblemTest // definition
{
};
// 24 BYTES INSTEAD OF 8, CARL!
static_assert(sizeof(void(ProblemTest::*)()) == 24);
The size of a member function pointer was trippled! And it cannot be shrunk back even after the definition of class ProblemTest has been seen by the compiler.
If you work with some third party libraries that rely on particular sizes of member function pointers on your compiler (e.g., the famous FastDelegate by Don Clugston), such unexpected size changes caused by some call to a type trait might be a real pain. Primarily because type trait invocations are not supposed to modify anything, yet, in this particular case, they do -- and this is extremely unexpected even for an experienced developer.
On the other hand, had we implemented our is_class using the __is_class intrinsic, everything would have been OK:
template<typename T>
struct my_good_is_class
: std::bool_constant<__is_class(T)>
{
};
class ProblemTest;
static_assert(my_good_is_class<ProblemTest>::value == true);
class ProblemTest
{
};
static_assert(sizeof(void(ProblemTest::*)()) == 8);
Invocation of my_good_is_class<ProblemTest> does not break any sizes in this case.
So, my advice is to rely on the compiler intrinsics when implementing your custom type traits like is_class wherever possible. That is, if you have a good reason to implement such type traits manually at all.
What does the T::* mean? Also, is this not a function declaration? It looks like one, yet this compiles without defining a function body.
The int T::* is a pointer to member object. It can be used as follows:
struct T { int x; }
int main() {
int T::* ptr = &T::x;
T a {123};
a.*ptr = 0;
}
Once again, is this not a function declaration with no body ever defined? Also what does the ellipsis mean in this context?
In the other line:
template<class T> two test(...);
the ellipsis is a C construct to define that a function takes any number of arguments.
I would like to understand what this code is doing.
Basically it's checking if a specific type is a struct or a class by checking if 0 can be interpreted as a member pointer (in which case T is a class type).
Specifically, in this code:
namespace detail {
template <class T> char test(int T::*);
struct two{
char c[2];
};
template <class T> two test(...);
}
you have two overloads:
one that is matched only when a T is a class type (in which case this one is the best match and "wins" over the second one)
on that is matched every time
In the first the sizeof the result yields 1 (the return type of the function is char), the other yields 2 (a struct containing 2 chars).
The boolean value checked is then:
sizeof(detail::test<T>(0)) == 1 && !std::is_union<T>::value
which means: return true only if the integral constant 0 can be interpreted as a pointer to member of type T (in which case it's a class type), but it's not a union (which is also a possible class type).
Test is an overloaded function that either takes a pointer to member in T or anything. C++ requires that the best match be used. So if T is a class type it can have a member in it...then that version is selected and the size of its return is 1. If T is not a class type then T::* make zero sense so that version of the function is filtered out by SFINAE and won't be there. The anything version is used and it's return type size is not 1. Thus checking the size of the return of calling that function results in a decision whether the type might have members...only thing left is making sure it's not a union to decide if it's a class or not.
Here is standard wording:
[expr.sizeof]:
The sizeof operator yields the number of bytes occupied by a non-potentially-overlapping object of the type of its operand.
The operand is either an expression, which is an unevaluated operand
([expr.prop])......
2. [expr.prop]:
In some contexts, unevaluated operands appear ([expr.prim.req], [expr.typeid], [expr.sizeof], [expr.unary.noexcept], [dcl.type.simple], [temp]).
An unevaluated operand is not evaluated.
3. [temp.fct.spec]:
[Note: Type deduction may fail for the following reasons:
...
(11.7) Attempting to create “pointer to member of T” when T is not a class type.
[ Example:
template <class T> int f(int T::*);
int i = f<int>(0);
— end example
]
As above shows, it is well-defined in standard :-)
4. [dcl.meaning]:
[Example:
struct X {
void f(int);
int a;
};
struct Y;
int X::* pmi = &X::a;
void (X::* pmf)(int) = &X::f;
double X::* pmd;
char Y::* pmc;
declares pmi, pmf, pmd and pmc to be a pointer to a member of X of type int, a pointer to a member of X of type void(int), a pointer to a member ofX of type double and a pointer to a member of Y of type char respectively.The declaration of pmd is well-formed even though X has no members of type double. Similarly, the declaration of pmc is well-formed even though Y is an incomplete type.

Need help to understand the purpose of a following class

The friend of mine send me an interesting task:
template<typename T>
class TestT
{
public:
typedef char ONE;
typedef struct { char a[2]; } TWO;
template<typename C>
static ONE test(int C::*);
template<typename C>
static TWO test(...);
public:
enum{ Yes = sizeof(TestT<T>::template test<T>(0)) == 1 };
enum{ No = !Yes };
};
I can't compile this code with VS2013. With GCC 4.9.0 it compiles. But I can't understand what it does.
The points of interest for me:
How it can work if functions have a declaration only but no definition?
What the TestT<T>::template test<T>(0) is? It looks like a function call.
What is this ::template means?
What's purpose of class above?
How is used principle called?
int C::* is a pointer to a int member, right?
It does not actually call the functions, it just looks at what the sizeof of the return type would be.
It is a function call. See below.
The template is necessary because of the dependent type problem.
It tests if there can be a pointer to a data member of the type parameter. This is true for class types only (e.g. for std::string but not for int). You can find code like this for example here which includes something very similar to your example - under the name of is_class.
SFINAE, which stands for "Substitution Failure Is Not An Error". The reason for this name becomes obvious once you realize that the substitution of C for int will fail and thus simply cause one of the function overloads to not exist (instead of causing a compiler error and aborting compilation).
Yes, it is a pointer that points to an int inside of an object of type C.
That's too many questions for a single question, but nevertheless:
sizeof doesn't evaluate its operand, it only determines the type. That doesn't require definitions for any functions called by the operand - the type is determined from the declaration.
Yes, that's a function call. If the class and function weren't templates, it would look like TestT::test(0).
template is needed because the meaning of the name test depends on the class template parameter(s), as described in Where and why do I have to put the "template" and "typename" keywords?.
It defines a constant Yes which is one if T is a class type and zero otherwise. Also a constant No with the logically inverted value.
It looks like it's intended for use in SFINAE, to allow templates to be partially specialised for class and non-class types. Since C++11, we can use standard traits like std::is_class for this purpose.
Yes, if C is a class type. Otherwise, it's a type error, so the overload taking that type is ignored, leaving just the second overload. Thus, the return type of test is ONE (with size one) if C is a class type, and TWO (with size two) otherwise; so the test for sizeof(...) == 1 distinguishes between class and non-class types.

Is a local class dependent if declared within a function template?

Current C++ compilers (latest gcc, clang) require the typename keyword in the example below:
template<class T>
struct A
{
};
template<class T>
void f(T)
{
struct C
{
};
typedef typename A<C>::Type Type; // typename required
}
If typename is omitted gcc (4.9, 5.0) reports the error:
need 'typename' before 'A<f(T)::C>::Type' because 'A<f(T)::C>' is a dependent scope
This example is otherwise well-formed according to my reading of the C++11 standard.
This behaviour seems to be covered by the following wording:
[temp.dep.type]/8
A type is dependent if it is
a template parameter,
a member of an unknown specialization,
a nested class or enumeration that is a member of the current instantiation,
a cv-qualified type where the cv-unqualified type is dependent,
a compound type constructed from any dependent type,
an array type constructed from any dependent type or whose size is specified by a constant expression
that is value-dependent,
a simple-template-id in which either the template name is a template parameter or any of the template
arguments is a dependent type or an expression that is type-dependent or value-dependent, or
denoted by decltype(expression), where expression is type-dependent.
However, according to [class.local] the class C is a local class rather than a nested class. If so, why should A<C> be treated as dependent?
EDIT
For bonus points, if the example is modified by adding a member enum to C as follows:
template<typename T>
struct A
{
typedef T Type;
};
template<class T>
void f(T)
{
struct C
{
enum { value = T::value };
};
typedef typename A<C>::Type Type; // typename required
}
Should A<C> now be treated as dependent?
According to my understanding (and the current wording of the standard), C in your example is not dependent. Neither is A<C>::Type, so the typename is not required.
There is a fundamental difference between nested classes of class templates and local classes in function templates: The latter cannot be specialized, thus any reference to a local class inside a function template is uniform. That is, in every specialization of f, C refers to the class C that is defined in this function template f. That is not the case with class templates as you can indeed explicitly specialize members on their own (as covered in [temp.expl.spec]
/(1.6)):
template <typename T>
class A { class C{}; };
template <>
class A<int>::C { int i; };
However:
A type is dependent if it is
a compound type constructed from any dependent type,
So if the definition was done as in dyp's example, C would be dependent as it is constructed from T.
There are unclarities in the standards wording that are being discussed in the comment section, e.g. about definitions of member functions that depend on T and how that transposes to the classes dependency.
Following is my reasoning, hope it helps. The local C does not instantiate until f instantiate. So, A<C> is not an instantiation and is opaque to the compiler when it sees it. Because of the opaqueness, the compiler cannot determine whether A<C>::Type is a nested type name or a data member or a method. However, by default, the compiler does not see A<C>::Type as a nested type name. Therefore, an explicit specification is needed.
There doesn't appear to be anything in the standard to state that the typename keyword should be necessary here. The wording does not explicitly state otherwise, either, which may have led GCC to take a bit of a shortcut in treating f<T>(T)::C (being a local class in a function template specialisation) as dependent on T — by extension, this would make A<[f<T>(T)::]C>::Type dependent.
Core defect 1484 wasn't raised for this issue specifically, but I think the additional non-normative text it proposes makes the intention clear and, were it in a standard, GCC would compliantly not require the typename keyword here.