If i have for example some template struct, and i want to give it a user-defined size for some member i can do it by passing a value to constructor like so:
template <typename T>
struct Foo {
int m_size;
Foo(int u_size)
:
m_size {u_size}
{
}
};
and i can also do it by having a non-type template parameter (kinda the way std::array does it), like so:
template <typename T, int u_size>
struct Foo {
int m_size;
Foo()
:
m_size {u_size}
{
}
};
My question is, what is the difference between these two methods, and when is it useful to use either of them?
You are using u_size to determine the initializer for the member m_size. The difference between the two examples boils down to Foo<T,i> being a different type than Foo<T,j>. Other than being instantiations of the same template (which usually does not mean much) they are totally unrelated. On the other hand, in the first case, any Foo<T> is of the same type Foo<T>, no matter what was the initial value for the member.
If m_size changes at runtime, it is questionable to require an instance that uses 42 as initial value and an instance that uses 24 as initial value to be of different types.
Maybe m_size does not change at runtime, then it can make sense to have the initial value as part of the type (like eg with std::array). Maybe it does change at runtime, but nevertheless there are reasons to have the initial value baked into the type. There is no "better" Or "worse", it depends what you want/need.
I'm trying to wrap my head around SFINAE.
We're using it to check whether a class has a method called "Passengers".
With some online examples, we constructed the following template classes.
#ifndef TYPECHECK
#define TYPECHECK
#include "../Engine/carriage.h"
namespace TSS{
template<typename T>
class has_passengers{
private:
typedef char one;
typedef struct{char a[2];} two;
template<typename C> static one test( decltype(&C::Passengers) );
template<typename C> static two test(...);
public:
static bool const value = sizeof(test<T>(0)) == sizeof(one);
};
template<typename T>
struct CarriageTypeCheck{
static_assert(has_passengers<T>::value, "Train initialized with illegal carriage");
};
}
#endif // TYPECHECK
I get the part how either of the two test-methods is chosen, but what I don't understand is why test<T> is initialized with 0 in the following line:
static bool const value = sizeof(test<T>(0)) == sizeof(one);
I can not see how the 0 is important for the check to work.
Another thing - why is decltype used?
The first overloaded function (potentially) takes a pointer to a class method, as a parameter. Due to C++'s legacy from C, the value 0 is convertible to a NULL pointer, or nullptr. So, if SFINAE does not kick out the first overloaded function, test<T>(0) becomes a valid function call, and its sizeof is equal to sizeof(one). Otherwise this resolves to the second overloaded function call.
And the short answer as to why decltype is used: otherwise it would not be valid C++. In a function declaration, the function's parameter must be types, specifying the types of the parameters to the function.
&C::Passengers is not a type (in the context of its intended use), so this would not be valid C++. decltype() of that automatically obtains the type of its argument, making it valid C++.
I can not see how the 0 is important for the check to work.
Because 0 could be used as the argument for both cases (i.e. the two overloaded test); for member pointer (treated as null pointer) and variadic arguments ....
Another thing - why is decltype used?
decltype is used for describing the type of member pointer (i.e. &C::Passengers) as the parameter of test.
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.
I have this template class:
template<typename T, T F(const std::string&)>
struct Builder
{
T operator()(const std::string& s) const { return F(s); }
typedef T type;
};
since I need a class holding a function and the value returned by the function (since I need a reference to it).
As you can see I have two template parameters, but actually the first is redundant. Is is possible to remove it in some way? Template alias? Something better than a macro
Return type T of the second template parameter must be defined before its first usage anyway (as the C++ rule states that any entity can be used only after its declaration), and the only way to declare is to use preceding type template parameter (as you did), so you cannot omit the first parameter.
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>
{ };