C++ template argument without a name - c++

I have come across the following code snippet:
template <typename T, typename = void>
struct test {
int t = sizeof(T);
};
I know that in typename = void, void is a default argument but it doesn't have a name! What is it useful for and what does it even mean?

This is used for specializations in conjunction with SFINAE. Doing this allows you to have code like
template <typename T, typename = void>
struct test {
int t = sizeof(T);
};
template <typename T>
struct test<T, std::enable_if_t<std::is_integral_v<T>>> {
// ^^ this part "fills in" the void ^^
int t = 42;
};
template <typename T>
struct test<T, std::enable_if_t<std::is_floating_point_v<T>>> {
// ^^ this part "fills in" the void ^^
int t = 21;
};
int main()
{
test<int> i;
std::cout << i.t << "\n";
test<double> d;
std::cout << d.t;
}
which outputs
42
21
Without the typename = void, we would not be able to add these specializations because there would be no second parameter the enable_if_t part could "fill in".

I personally like to see it as a case of default template (type)argument to sfinae out overloads which does not meet certain criteria.
First thing first, giving name to a default template argument is just fine, so the following is correct:
template <typename T, typename sometype= void>
struct test {
int t = sizeof(T);
};
In the above case , clearly the type argument sometype is not used anywhere in the struct test. But what if instead of setting default value to void, we set it using some compile time conditions so that the template function is only valid for integral types like so ?
(borrowing code's from nathan's answer)
template <typename T>
struct test<T, typename sometype = std::enable_if_t<std::is_integral_v<T>>> {
int t = 42;
};
If the T has type integral then sometype is defined otherwise the given template is ignored making use of sfinae.
Additionally, you can drop "sometype" to write :
template <typename T>
struct test<T, typename = std::enable_if_t<std::is_integral_v<T>>> {
int t = 42;
};
Finally compare this with the default values used in function declarations:
void foo(int = 9); //Function declaration can have default values without names too.
void foo (int a )
{
//some code
}

Related

How to make traits to accept a parameter pack?

I define some type traits like this:
template <typename T>
struct has_something
{
static constexpr bool value = false;
};
template <>
struct has_something<int>
{
static constexpr bool value = true;
};
template <typename T>
constexpr bool has_something_v = has_something<T>::value;
And a function template which is has_something_v is a requirement for function parameter:
template <typename T, typename = std::enable_if_t<has_something_v<T>>>
void some_function(const T temp)
{
}
When i call it with wrong type:
struct wrong_type
{
};
void f ()
{
some_function(wrong_type());
}
compiler give me a proper error message:
/tmp/untitled/main.cpp:23: candidate template ignored: requirement 'has_something_v<wrong_type>' was not satisfied [with T = wrong_type]
but when i called with another template function:
template <typename ...T, typename = std::enable_if_t<has_something_v<T...>>>
void some_function(const T... args)
{
(some_function(args), ...);
}
void f ()
{
some_function(1, 2, a());
}
compiler give me really bad and confusing error message because i don't have a parameter pack acceptable traits :
Compiler error message
And if i remove std::enable_if from last template function, everything work fine until i send a wrong_type type to function which result is in crashing program.
For parameter pack, i wrote this:
template <typename ...T>
struct has_something
{
static bool value;
static constexpr bool c(T... args)
{
value = (args && ...);
return value;
}
};
template <>
struct has_something<int>
{
static constexpr bool value = true;
};
template <typename ...T>
const bool has_something_v = has_something<T...>::value;
But it still fail.
How could i write a acceptable parameter pack type traits ?
If you want to make the trait accept a parameter pack and it's value be true only when the parameter pack has a single type and that type is int you need to change only little on your code:
#include <iostream>
#include <type_traits>
template <typename...T>
struct has_something : std::false_type {};
template <>
struct has_something<int> : std::true_type {};
template <typename... T>
constexpr bool has_something_v = has_something<T...>::value;
int main() {
std::cout << has_something_v<int>;
std::cout << has_something_v<double>;
std::cout << has_something_v<int,double>;
}
Using std::true_type and std::false_type makes traits a bit shorter to write. I only had to make the trait accept a parameter pack, the specialization can stay the same.
Last but not least you should pick a better name. For example is_one_int would be much better than something.
PS: SFINAE can be used to create compiler errors, but often a simple static_assert is the better choice to get a clean message:
template <typename...T>
void foo(T...args) {
static_assert( is_one_int_v<T...>, " put nice message here");
}
SFINAE is the tool of choice when you want to disambiguate different overloads, but if a function should simply fail without alternative then a static_assert is simpler.

Why a template specialization cannot change the return type?

After reading this question I had to realize once more how little I know about templates. I can understand, that a template specialization like this
// A
template <typename T> void foo(T x){}
template <> void foo<double>(int x){}
cannot work (error: template-id 'foo<double>' for 'void foo(int)' does not match any template declaration). Not only would it make little sense, but also parameter deduction would have no chance to get the right T. However, I do not understand why it does not work for return types:
// B
template <typename T> int foo(T x){}
template <> double foo<double>(double x){}
(similar error as above). Actually I dont have any particular use case at hand, but still I would be interested in how to choose a return type depending on T. As a workaround I found this:
// C
template <typename T> struct foo { static int moo(T x){return x;} };
template <> struct foo<double> { static double moo(double x){return x;} };
So it is possible to choose the return type depening on T. However, I am still puzzled...
What is the reason for B being not possible?
Even if strange, you may have
template <typename T>
void foo(int);
template <typename T>
char foo(int);
Demo
So your specialization would be ambiguous.
Actually, you can work around it either by using a template parameter for the return type or a traits class.
As an example:
#include<type_traits>
template<typename T>
T f() { return T{}; }
template<typename>
struct Traits;
template<>
struct Traits<int> {
using ReturnType = char;
};
template<>
struct Traits<char> {
using ReturnType = int;
};
template<typename T>
typename Traits<T>::ReturnType g() { return T{}; }
int main() {
static_assert(std::is_same<decltype(f<int>()), int>::value, "!");
static_assert(std::is_same<decltype(f<double>()), double>::value, "!");
static_assert(std::is_same<decltype(g<int>()), char>::value, "!");
static_assert(std::is_same<decltype(g<char>()), int>::value, "!");
}
In the case of g, if parameters are deduced you have that two apparently identical calls have different return types.
That said, specializations don't allow the user to change the declaration of a function.
That's why you have to play with such a definition to have different return types for different template arguments.
1. Default template parameters
Your case "C" may be easily worked around with default template parameters:
template<typename T, typename U = int>
U foo(T x) {
return x;
}
template<>
double foo<double, double>(double x) {
return x;
}
Now foo may be used like a function with single template argument:
auto a = foo(5);
auto b = foo(1.0);
auto c = foo<short>(5);
2. Type map
Another approach is much uglier, but somewhat more universal. It will require you to enumerate all possible return types in one place, allowing you to choose any of those return types based on template parameter type. The crux of this solution is just a compile-time type map. It can be implemented variously using pairs, tuples, and tuple_elements, but let's stop on a minimalistic implementation:
struct last_key{};
struct last_value{};
template<typename key, typename k = last_key, typename v = last_value, typename ...pairs>
struct type_map {
static_assert(sizeof...(pairs) % 2 == 0, "Last key does not have a value");
using type = typename std::conditional<std::is_same<key, k>::value,
v,
typename type_map<key, pairs...>::type>::type;
};
template<typename key>
struct type_map<key> {
using type = int;
};
The map "returns" value type for a given key type or int if key not found. Having the map, let's declare a return type which depends on a single template parameter:
template<typename key>
using return_type = typename type_map<key, double, double>::type;
And finally your example case "C" will again be solved by the only declaration of foo:
template<typename T>
auto foo(T x) -> return_type<T> {
return x;
}
But if you want, you still may add specialization with different behavior, which will compile and work correctly:
// Specialization.
template<>
auto foo(double x) -> double {
return x;
}
Now both with or without specialization, the following code:
auto a = foo(1);
auto b = foo(1.0);
std::cout << std::is_same<decltype(a), int>::value << std::endl;
std::cout << std::is_same<decltype(b), double>::value << std::endl;
will print
1
1

Access type member

In my example I have a class Foo<T>. In my function test I need to get the template parameter of Foo otherwise the normal type. First I started to use std::conditional but forgot that the template parameters must all be valid, no matter which one is picked. Is the only way to create a type-specialisation for non-Foo types?
Example
#include <type_traits>
template <typename TYPE>
class Foo
{
public:
using M = TYPE;
};
template <typename T>
void test(const T& a)
{
// actually I would have used !is_foo<T>::value for the first arg
// but this check is fine to minimise the example
using MY_TYPE = typename std::conditional<
std::is_same<T, int>::value,
T,
typename T::M>::type; // <---Error: error: type 'int' cannot be used prior to '::' because it has no members
}
int main()
{
test(Foo<int>()); // MY_TYPE must be int
test(int()); // MY_TYPE must be int
return 0;
}
Well you could make an UnFoo helper to get the right type for you:
template <typename T>
struct UnFoo {
using type = T;
};
template <typename T>
struct UnFoo<Foo<T>> {
using type = T;
};
template <typename T>
void test(const T& a)
{
using MY_TYPE = typename UnFoo<T>::type; //maybe with a helper to get rid of typename
}
Another option would be to write an overload for Foo<T> and have it delegate to the other function, but that depends on what your real test function does.
You can do some void_t magic to allow SFINAE to figure help you out:
#include <type_traits>
#include <iostream>
#include <typeinfo>
template <typename TYPE>
class Foo
{
public:
using M = TYPE;
};
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
// primary template handles types that have no nested ::T member:
template< class T, class = void_t<> >
struct M_or_T { using type = T; };
// specialization recognizes types that do have a nested ::T member:
template< class T >
struct M_or_T<T, void_t<typename T::M>> { using type = typename T::M; };
template <typename T>
void test(const T& a)
{
using MY_TYPE = typename M_or_T<T>::type;
std::cout << typeid(MY_TYPE).name() << "\n";
}
int main()
{
test(Foo<int>()); // MY_TYPE must be int
test(int()); // MY_TYPE must be int
return 0;
}
What happens is that the second overload of M_or_T substitution fails for int (and for any type without a type member M) and thus the first overload is chosen. For types which have a type member M, a more specialized second overload is chosen.
#include <type_traits>
template <typename TYPE>
class Foo
{
public:
using M = TYPE;
};
template <typename T>
void test(const Foo<T>& a)
{
using MY_TYPE = Foo<T>::M;
testOther<MY_TYPE>(a);
}
template <typename T>
void test(const T& a)
{
using MY_TYPE = T;
testOther<MY_TYPE>(a);
}
template <typename T, typename S>
void testOther(const S& a)
{
// do stuff
}
int main()
{
test(Foo<int>()); // MY_TYPE must be int
test(int()); // MY_TYPE must be int
return 0;
}
I'm not exactly sure what you wanted, but I hope this is what you wanted. It might be a bit off. I didn't compile this.

Possible to use type_traits / SFINAE to find if a class defines a member TYPE?

I have seen this question which allows one to check for the existence of a member function, but I'm trying to find out whether a class has a member type.
In the example below, both evaluate to "false", but I would like to find a way so that has_bar<foo1>::value evaluates to false, and has_bar<foo2>::value evaluates to true.
Is this possible?
#include <iostream>
struct foo1;
struct foo2 { typedef int bar; };
template <typename T>
class has_bar
{
typedef char yes;
typedef long no;
template <typename C> static yes check( decltype(&C::bar) ) ;
template <typename C> static no check(...);
public:
enum { value = sizeof(check<T>(0)) == sizeof(yes) };
};
int main()
{
std::cout << has_bar<foo1>::value << std::endl;
std::cout << has_bar<foo2>::value << std::endl;
return 0;
}
Edit: implementing a specialisation in response to the answers below:
...if you use C::bar in the target template, the template will be
discarded automatically for types that don't have that nested type.
I have tried to do this, but am clearly missing something
#include <iostream>
struct foo1;
struct foo2 { typedef int bar; };
template <typename T, typename U = void>
struct target
{
target()
{
std::cout << "default target" << std::endl;
}
};
template<typename T>
struct target<T, typename T::bar>
{
target()
{
std::cout << "specialized target" << std::endl;
}
};
int main()
{
target<foo1>();
target<foo2>();
return 0;
}
Try this
template<class T>
struct Void {
typedef void type;
};
template<class T, class U = void>
struct has_bar {
enum { value = 0 };
};
template<class T>
struct has_bar<T, typename Void<typename T::bar>::type > {
enum { value = 1 };
};
You cannot obtain a pointer to member to a type member:
template <typename C> static yes check( decltype(&C::bar) ) ;
The subexpression &C::bar will only be valid when bar is a non-type member of C. But what you need to check is whether it is a type. A minimal change to your template could be:
template <typename C> static yes check( typename C::bar* ) ;
If bar is a nested type of C, then that function overload will be a valid candidate (the 0 will be a pointer to whatever C::bar type is), but if C does not contain a nested bar then it will be discarded and the second test will be the only candidate.
There is a different question as of whether the trait is needed at all, since if you use C::bar in the target template, the template will be discarded automatically for types that don't have that nested type.
EDIT
What I meant is that in your approach you need to create a trait for each and every possible nested type, just to generate a template that does or does not hold a nested type (enable_if). Let's take a different approach... First we define a general utility to select a type based on a condition, this is not required for this problem, and a simpler template <typename T> void_type { typedef void type; }; would suffice, but the utility template can be useful in other cases:
// General utility: if_<Condition, Then, Else>::type
// Selects 'Then' or 'Else' type based on the value of
// the 'Condition'
template <bool Condition, typename Then, typename Else = void>
struct if_ {
typedef Then type;
};
template <typename Then, typename Else>
struct if_<false, Then, Else > {
typedef Else type;
};
Now se just need to use SFINAE for class template specializations:
template <typename T, typename _ = void>
struct target {
// generic implementation
};
template <typename T>
struct target<T, typename if_<false,typename T::bar>::type> {
// specialization for types holding a nested type `T::bar`
};
Note that the main difference with your approach is the use of an extra intermediate template (the one for which Substitution will Fail --and Is Not An Error) that yields a void type (on success). This is the reason why the void_type template above would also work: you just need to use the nested type as argument to a template, and have that fail, you don't really care what the template does, as long as the evaluation is a nested type (that must be void) if it succeeds.
In case it is not obvious (it wasn't at first for me) why your approach doesn't work, consider what the compiler needs to do when it encounters target<foo2>: The first step is finding that there is a template called target, but that template takes two arguments of which only one was provided. It then looks in the base template (the one that is not specialized) and finds that the second argument can be defaulted to void. From this point on, it will consider your instantiation to be: target<foo2,void> (after injecting the defaulted argument). And it will try to match the best specialization. Only specializations for which the second argument is void will be considered. Your template above will only be able to use the specialized version if T::bar is void (you can test that by changing foo2 to: struct foo2 { typedef void bar; }. Because you don't want the specialization to kick in only when the nested type is void you need the extra template that will take C::bar (and thus fail if the type does not contain a nested bar) but will always yield void as the nested type.
C++20 Update:
It is now much more easier to check whether a given type contains a specific type definition.
template<typename T>
concept has_bar = requires {
typename T::bar;
};
... so your example code evolves to this:
#include <iostream>
struct foo1;
struct foo2 { typedef int bar; };
template <typename T, typename U = void>
struct target
{
target()
{
std::cout << "default target" << std::endl;
}
};
template<typename T>
requires(has_bar<T>)
struct target<T>
{
target()
{
std::cout << "specialized target" << std::endl;
}
};
int main()
{
target<foo1>();
target<foo2>();
return 0;
}
Example on gcc.godbolt: https://gcc.godbolt.org/z/a15G13
I prefer to wrap it in macro.
test.h:
#include <type_traits>
template<typename ...>
struct void_type
{
using type = void;
};
template<typename ...T>
using void_t = typename void_type<T...>::type;
#define HAS_TYPE(NAME) \
template<typename, typename = void> \
struct has_type_##NAME: std::false_type \
{}; \
template<typename T> \
struct has_type_##NAME<T, void_t<typename T::NAME>>: std::true_type \
{} \
HAS_TYPE(bar);
test.cpp:
#include <iostream>
struct foo1;
struct foo2 { typedef int bar; };
int main()
{
std::cout << has_type_bar<foo1>::value << std::endl;
std::cout << has_type_bar<foo2>::value << std::endl;
return 0;
}

How to use enable_if to enable member functions based on template parameter of class

In code:
template<class T>
struct is_builtin
{
enum {value = 0};
};
template<>
struct is_builtin<char>
{
enum {value = 1};
};
template<>
struct is_builtin<int>
{
enum {value = 1};
};
template<>
struct is_builtin<double>
{
enum {value = 1};
};
template<class T>
struct My
{
typename enable_if<is_builtin<T>::value,void>::type f(T arg)
{
std::cout << "Built-in as a param.\n";
}
typename enable_if<!is_builtin<T>::value,void>::type f(T arg)
{
std::cout << "Non - built-in as a param.\n";
}
};
struct A
{
};
int main()
{
A a;
My<int> m;
My<A> ma;
m.f(1);
ma.f(a);
return 0;
}
I'm getting an error:
error C2039: 'type' : is not a member of 'std::tr1::enable_if<_Test,_Type>'
Obviously I don't understand how to use enable_if. What I was thinking was that I can enable one or the second one member function from a set of member functions during compilation time but it does not work. Could anyone please explain to me how to do it correctly?
Edited
What I really can't understand is why isn't there typedef in one of those def. Compiler cannot find it and it wont compile it.
You can't use class template parameters to get SFINAE for member functions.
You either need to
make the member function a member function template instead and use enable_if on the member function template's template parameters or
move the member function f into a policy class and specialize the class template using enable_if.
Here's how it works (note that for convenience I replaced your is_builtin trait with std::is_arithmetic and used further C++11 stuff, but it works any way):
template<class T>
struct My
{
template<typename T_ = T, std::enable_if_t<std::is_arithmetic<T_>::value>* = nullptr>
void f(T_ arg)
{
std::cout << "Built-in as a param.\n";
}
template<typename T_ = T, std::enable_if_t<!std::is_arithmetic<T_>::value>* = nullptr>
void f(T_ arg)
{
std::cout << "Non - built-in as a param.\n";
}
};
DEMO
The crucial part is to bring the template parameter into the immediate context by using a default function template parameter T_ which equals the class template parameter T. For more details, see this question.
You can fix your code by using modified enable_if
template < typename T >
struct __Conflict {};
template <bool B, class T = void>
struct __enable_if { typedef __Conflict<T> type; };
template <class T>
struct __enable_if<true, T> { typedef T type; };
Example of usage:
template <typename T>
class Lazy
{
public:
void _ctor(bool b);
void _ctor(typename __enable_if<!std::is_same<T, bool>::value, T>::type);
};
template <typename T>
void Lazy<T>::_ctor(bool b)
{
std::cout << "bool " << b << std::endl;
};
template <typename T>
void Lazy<T>::_ctor(typename __enable_if<!std::is_same<T, bool>::value, T>::type t)
{
std::cout << "T " << t << std::endl;
};
int main(int argc, char **argv)
{
Lazy<int> i;
i._ctor(10);
i._ctor(true);
Lazy<bool> b;
b._ctor(true);
return 0;
}
enable_if expects a metafunction. To use a bool you need enable_if_c. I'm surprised you're not getting errors explaining THAT problem.
You can fix your metafunction by declaring a 'type' typedef inside that is simply itself. Then you can use boost::enable_if<is_builtin<T>>::type