Comparison : C++ template specialization approaches - c++

Which is more correct? And Why.
On work I recently run in a discussion how to do a specific template specialization.
This way:
template <typename T, bool someBoolVar = is_polymorphic<T>::value>
struct SomeTemplate { // with empty definition
};
template <typename T>
struct SomeTemplate<T, true> {
...
};
template <typename T>
struct SomeTemplate<T, false> {
...
};
or this way:
template <typename T, bool someBoolVar = is_polymorphic<T>::value>
struct SomeTemplate; // without empty definition -- difference here
template <typename T>
struct SomeTemplate<T, true> {
...
};
template <typename T>
struct SomeTemplate<T, false> {
...
};

Neither. Because both will not compile! Wrong syntax for partial specialization!
This is how partial specialization is done:
//correct syntax
template <typename T>
struct SomeTemplate<T,false> {
...
};
Not this:
//wrong syntax
template <typename T, false>
struct SomeTemplate {
...
};
Now answer to your question assuming you'll fix the syntax!
In my opinion, the second approach is rational, because bool can have ONLY two values, so three versions of SomeTemplate class template doesn't make sense at all, which you're doing in the first approach.

The second way will generate a compiler error if you try to use the template in a way that isn't specialized. The first way just gives you an empty class in those cases, which may or may not generate an error later on when you try to use the class.
The kicker here is that there are only two values for bool and you've specialized for both, so it really doesn't matter which way you go. The empty class won't be linked and thus doesn't generate any extra code.
This specific case is like the compile-time-assertion pattern:
template<bool test> struct compiler_assert;
template<> struct compiler_assert<true> {};
// ...
compiler_assert<bool_test_goes_here> assert1;
Which stops the compile if the test evaluates to false.

Both examples have syntax errors. Assuming you fix them, there isn't any difference between the two. Empty implementation, which you provided in the first example can never be used, so no code generated.

Related

How to force SFINAE to choose the second definition of structure?

Before that I want to tell that I have tried to implement is_assignable on my own. There is no need to show me another examples - I have already seen some implementation.
I would like to fix my solution thanks to you (if it's possible, of course) that'll work out.
So, here is my code:
#include <iostream>
#include <type_traits>
#include <utility>
template<typename LambdaT>
struct is_valid_construction {
is_valid_construction(LambdaT) {}
typedef typename LambdaT lambda_prototype;
template<typename ValueTypeT, typename ExprTypeT = decltype(std::declval<lambda_prototype>()(std::declval<ValueTypeT>()))>
struct evaluate {
evaluate(ValueTypeT val) {
std::cout << "Right!";
}
typedef typename std::true_type value;
};
template<typename ValueTypeT> //The compiler ignores this definition
struct evaluate<ValueTypeT, decltype(std::declval<lambda_prototype>()(std::declval<int>()))> {
evaluate(ValueTypeT val) {
std::cout << "Nope";
}
typedef typename std::false_type value;
};
template<typename ValueTypeT>
void print_value(ValueTypeT val) {
evaluate evaluation(val);
}
};
struct ForTest {};
int main() {
is_valid_construction is_assignable([](auto x) -> decltype(x = x) { });
is_valid_construction is_less_comparable([](auto x) -> decltype(x < x) {});
is_valid_construction is_more_comparable([](auto x) -> decltype(x > x) {});
is_assignable.print_value(int{});
is_less_comparable.print_value(char{});
is_more_comparable.print_value(ForTest{});
return 0;
}
As you can see I am trying to define template structure within template structure. So, I excepted that if the invocation (with declval) of this lambda-expression with parameter of this type (rougly, in terms of substitution) is failed, then SFINAE goes further and should see that the second template definition could be convenient for instantiation. I am asking how could I fix my template structure and its default parameter to push SFINAE use the second definition?
SFINAE can be used in order to direct the compiler to choose a particular function overload, or a particular partial specialization of a class template. In the first case, substitution failures remove declarations from the overload set and in the second case, substitution failures remove the partial specialization declarations from consideration (causing either the primary template to be used, or a different partial specialization for which substitution succeeds).
But what you are trying to do here is backward: you have a situation where the primary template is potentially subject to substitution error, and you provide a partial specialization as an alternative. This can never work. Partial specialization matching begins after the template argument list to the primary template is fully known, therefore if a substitution error occurs in the primary template's template argument list, no specializations can be considered.
For example if we have
template <typename T, typename U = some_metafunction_of_T>
struct S;
template <typename T>
struct S<T, T>;
then the instantiation process of S<int> will first evaluate U for the primary template, and then, only once T and U are both known, the compiler can determine whether or not they are the same (which would allow the partial specialization to be used). If a substitution error occurs while computing U, the question of whether the partial specialization applies cannot even be asked.
To fix your code, you would have to switch the two definitions of evaluate. The primary template would have to be the "fallback", and the partial specialization would have to be potentially subject to substitution error.
as #Brian said, you should put the requirements at the primary template if the requirements are for all specializations, and put other requirements for each specialization at their own declarations:
template<typename T, typename = std::void_t</* global requirements */>>
struct S;
template<typename T>
struct S<T, std::void_t</* requirements for this specialization */>>;
and if you want one of specialization is prior to others, you can add its negative requirements to other specializations:
template<typename T, typename = std::void_t</* global requirements */>>
struct S;
template<typename T>
struct S<T, std::void_t<std::enable_if_t</* conditions for this specialization */>>>;
template<typename T>
struct S<T, std::void_t<std::enable_if_t<!/* conditions for the former specialization */>, /* requirements for this specialization */>>;
for your example, it should be like this:
template<typename Lambda>
struct is_valid_construction{
template<typename T, typename = void>
struct helper : std::false_type{};
template<typename T>
struct helper<T, std::void_t<decltype(std::declval<Lambda>()(std::declval<T>()))>> : std::true_type{};
template<typename V, typename = void>
struct evaluate;
template<typename V>
struct evaluate<V, std::enable_if_t<helper<V>::value>>;
template<typename V>
struct evaluate<V, std::void_t<std::enable_if_t<!helper<V>::value>, decltype(std::declval<Lambda>()(std::declval<int>()))>>;
};
by the way, you can use std::is_invocable to simplify this code:
template<typename Lambda>
struct is_valid_construction{
template<typename V, typename = void>
struct evaluate;
template<typename V>
struct evaluate<V, std::enable_if_t<std::is_invocable_v<Lambda, V>>>;
template<typename V>
struct evaluate<V, std::enable_if_t<!std::is_invocable_v<Lambda, V> && std::is_invocable_v<Lambda, int>>>;
};
Thanks to #RedFog and #Brian I could complete my code and I have got the such result:
#include <iostream>
#include <type_traits>
#include <utility>
template<typename LambdaT>
struct is_valid_construction {
is_valid_construction(LambdaT) {}
typedef LambdaT lambda_prototype;
template<class ValueT, class = void>
struct is_void_t_deducable : std::false_type {};
template<class ValueT>
struct is_void_t_deducable<ValueT,
std::void_t<decltype(std::declval<lambda_prototype>()(std::declval<ValueT>()))>> : std::true_type {};
template<class ValueT>
bool is_valid_for(ValueT value) {
if constexpr (is_void_t_deducable<ValueT>::value)
return true;
else
return false;
}
};
struct ForTest {};
int main() {
is_valid_construction is_assignable([](auto x) -> decltype(x * x) { });
std::cout << is_assignable.is_valid_for(0) << std::endl;
std::cout << is_assignable.is_valid_for(ForTest{});
return 0;
}
As they both said, that when I had declared template parameter like that:
template<typename ValueTypeT, typename ExprTypeT = decltype(std::declval<lambda_prototype>()(std::declval<ValueTypeT>()))>
the compiler didn't understand what a default value should the second template parameter assign and since both declarations are incompatible.
I am new one in template programming and I can try to explain the solution as simple as possible:
The second template parameter is (if to say not strictly!) should be void. So, the compiler can instantiate the template with second void parameter in two ways by means of first declaration or second declaration.
(It should be said that std::void_t<TemplateParam> becomes void if TemplateParam is well!)
If an instantiation with the second declaration is well, then the
second template parameter is void.
If an instantiation with the first declaration is well, then the
second template parameter is void.
So, we should help compiler to deduce both structures with the second template parameter void. When it tries to instantiate is_valid_for(ForTest{}) first of all it tries to deduce
std::void_t<decltype(std::declval<lambda_prototype>()(std::declval<ValueT>()))>
but gets substitution error. However, nothing prevents to deduce the second template parameter void in another way and the compilers takes the first declaration.
P.S. I know that this explanation is not good but it may help dummies like me!

Using a specialization of variadic template as a template argument

Consider the following:
template <class...>
struct MyT;
template <class T>
struct MyT<T> {};
template <template <class> class TT = MyT> struct A {}; // fine
using B = A<MyT>; // does not compile
int main() {
return 0;
}
When MyT is used as a default argument of A, the compiler (g++ 5.4.0) is happy. However, when it is used to instantiate A, the story is different:
temp.cpp:19:16: error: type/value mismatch at argument 1 in template parameter list for ‘template<template<class> class TT> struct A’
using B = A<MyT>;
^
temp.cpp:19:16: note: expected a template of type ‘template<class> class TT’, got ‘template<class ...> struct MyT’
I can fix it by introducing an alias:
template <class T>
using MyTT = MyT<T>;
using B = A<MyTT>; // fine
The question: what is the reason for the error and is there a solution without introducing an alias?
EDIT Please note that A is declared to have a template template parameter as shown and that is not given for change.
You cannot do that and you cannot use such a type as a default parameter. The fact that it seems to be accepted as long as you don't rely on it doesn't mean that the default parameter is a valid one.
Consider the following code that explicitly uses the default type:
template <class...>
struct MyT;
template <class T>
struct MyT<T> {};
template <template <class> class TT = MyT> struct A {}; // fine
int main() {
A<> a;
return 0;
}
The error is quite clear:
template template argument has different template parameters than its corresponding template template parameter
Partial specializations are not taken in account in this case, thus the two declarations differ.
You should either declare A as:
template <template <class...> class TT = MyT> struct A;
Or declare somewhere a type that is constrained to a single argument, as an example by means of an using declaration as you did.
First, the default argument doesn't work either.
Second, template template arguements are a strange beast. It would make sense if a template template argument would take anything that could be instantiated with the signature described in the template template argument.
That is not how it works.
Instead it works the other way around.
template<template<class...>class Z> struct foo {};
template<template<class >class Z> struct bar {};
template<class...>struct a{};
template<class >struct b{};
foo will accept a or b.
bar will accept only b.
The correct response to this, once you understand it, is "what the hell?". If you aren't responding "what the hell" back up and see if you can understand it. This basically works backwards from typical typing for arguements in C++; it behaves more like a return type than an argument. (Learn the terms contravariance and covariance if you want to see some of the language that lets you talk about this directly)
This is quite non-intuitive, and why it works this way exactly would involve tracking down the pre-history of C++.
But, as a benefit, a template<class...>class argument is in effect an "any template that only takes type parameters". I find this highly useful.
As a downside, template<class>class arguements are almost completely useless.
Tl;dr: make your template<template parameters be template<template<class...>class, and metaprogram only with templates that only take types. If you have a template that takes values, write a type wrapper that replaces a requirement for a std::size_t X with a std::integral_constant< std::size_t, X >.
Forgetting for a moment the question of "Why would you do this?",
the first version would work if you hadn't done any template specialization.
template <class T>
struct MyT { };
template <template <class> class TT = MyT> struct A
{};
using B = A<MyT>;
With template specialization, the compiler must determine the best match, but since you haven't ever actually provided any template arguments it's ambiguous.
When you introduce MyTT you are using a single template argument, and the compiler is smart enough to see that you have a specialization when there is only one arg:
template <class T>
using MyTT = MyT<T>;
It chooses the specialization instead of the variadic version in this case.
But now we circle back to the grand question... why? Unless within A you're always instantiating MyT with a specific class, it's pointless to use A at all:
template<template<class> class TT = MyT> struct A
{
// use an instance of TT??
TT<int> myInstance; // forced to choose `int`
};
I would like to split your question into 2 parts.
A) Consider the template of your structure is simpler
template <class T>
struct TestStruct {
};
template <
template <class>
class TT = TestStruct
>
struct A
{
int a; // sorry to modify this. This help to show how it works
};
int main() {
A< TestStruct > b;
b.a; // it works!
return 0;
}
It works because of the template class TT only accept the template with < class... > template. The specializated class is not count on this ( because the underlying of it is still template < class ... > )
B) even you update your struct A to the template< class... > one, you still have one more problem. What is the template argument of TT? Please see the example below
template <class...>
struct MyT;
template <class T>
struct MyT<T> {
int a;
};
template <
template <class...>
class TT = MyT
// may be you need to add some more typename here, such as
// typename T1, ... , and then TT<T1> a;
>
struct A
{
TT<int> a;
// Here ! TT is a template only, do not have the template parameters!!!
};
int main() {
A< MyT > b;
b.a; // it works!!
return 0;
}
But, if you really cannot update the signature of those definitions, you can do a proxy class
template< class T >
struct Proxy : MyT<T>
{
};

C++ Alias to Template?

I'm trying to create an alias to a template, rather than a type and I can't find the syntax to do it. Below is an example that demonstrates my problem. My guess is this is just something that can't be done, but I'm hoping someone can prove me wrong. If it can't be done, is there some underlying reason it doesn't make sense to do this, or is it just not implemented?
template <class S>
class Down;
template <class S>
class Up {
template <class S1>
using Opposite = Down<S1>;
};
template <class S>
class Down {
template <class S1>
using Opposite = Up<S1>;
};
template <template <typename> class Direction>
void oneDirection() {
//Call another function here that uses the template argument as a template
}
template <template <typename> class Direction>
void bothDirections() {
oneDirection<Direction>();
oneDirection<Direction::Opposite>(); //This doesn't compile
}
int main() {
bothDirections<Up>();
}
In Direction::Opposite, Direction:: is a nested-name-specifier, and it can't indeed denote a class template (you'd need to give it the required template arguments to make it a template specialization).
I suppose one reason to not allow that form is that class templates can have partial or explicit specializations, which can provide different members from the primary template, so the compiler needs to work with a specific specialization to be able to know exactly what's available in there.
You can work around this by using traits to associate the two templates:
template<class> class Up { };
template<class> class Down { };
template<template<class> class Direction> struct Direction_traits;
template<> struct Direction_traits<Up>
{
template<class S1> using Opposite = Down<S1>;
};
template<> struct Direction_traits<Down>
{
template<class S1> using Opposite = Up<S1>;
};
template<template<class> class Direction>
void oneDirection() {
//Do something here
}
template<template<class> class Direction>
void bothDirections() {
oneDirection<Direction>();
oneDirection<Direction_traits<Direction>::template Opposite>();
}
int main() {
bothDirections<Up>();
}
However, keep in mind that Direction_traits<Up>::Opposite is not the same template as Down, at least not yet - the language rules may change in the future, more details in this answer and its comments.
This could cause problems if you want to get back to Up from inside oneDirection<Direction_traits<Up>::Opposite> using the traits - there won't be a trait specialization defined for the alias template. Things would need to get a bit more complicated to allow such use; a possible solution is outlined in the answer quoted above.

signed/unsigned trait programming

I'm starting to learn about traits and templates in c++. What I'm wondering is is it possible to create templates for signed/unsigned integral types. The idea is that the normal class would (probably) be implemented for singed integer types, and the variation for unsigned integer types. I tried:
template <typename T>
class FXP<T>
{ ... };
template <typename T>
class FXP<unsigned T>
{ ... };
but this does not compile.
I even came across:
std::is_integral
std::is_signed
std::is_unsigned
So, how do I put these in action to define a class that only supports these two variants?
In this case, there's a few ways to go about it, but my favorite for cases where there's a limited number of variants (e.g., a boolean or two saying which way it should behave), partial specialization of a template is usually the best way to go:
// Original implementation with default boolean for the variation type
template <typename T, bool is_unsigned = std::is_unsigned<T>::value>
class FXP {
// default implementation here
};
Your next step is to then provide a partial specialization that takes the typename T, but only works for a specific variant of the template parameters (e.g. true or false).
template <typename T>
class FXP<T, false> {
// partial specialization when is_unsigned becomes false
};
template <typename T>
class FXP<T, true> {
// partial specialization when is_unsigned becomes true
};
In this case, if you write a default implementation, you only need to make a specialization for the case that's non-default (like the true case).
Here's an example, where the default case gets overridden by a specialized template parameter:
http://coliru.stacked-crooked.com/a/bc761b7b44b0d452
Note that this is better only for smaller cases. If you need complex tests, you're better off using std::enable_if and some more complicated template parameters (like in DyP's answer).
Good luck!
With an additional template parameter:
#include <iostream>
#include <type_traits>
template <typename T, class X = void>
struct FXP
{
// possibly disallow using this primary template:
// static_assert(not std::is_same<X, X>{},
// "Error: type neither signed nor unsigned");
void print() { std::cout << "non-specialized\n"; }
};
template <typename T>
struct FXP< T, typename std::enable_if<std::is_signed<T>{}>::type >
{ void print() { std::cout << "signed\n"; } };
template <typename T>
struct FXP< T, typename std::enable_if<std::is_unsigned<T>{}>::type >
{ void print() { std::cout << "unsigned\n"; } };
struct foo {};
int main()
{
FXP<foo>().print();
FXP<int>().print();
FXP<unsigned int>().print();
}

Is there a way to bind a template<template> parameter?

Context
I have a custom comparator that takes another comparator and applies an additional check:
template <template <typename> class Comparator, typename T>
struct SoftOrder : public std::binary_function<T, T, bool> {
bool operator()(const T lhs, const T rhs) const {
return Comparator<T>()(lhs, rhs) && AnotherCheck();
}
};
I have a second class that accepts a comparator, e.g.:
template <template <typename> class Comparator>
class Processor { ... };
It is easy to instantiate a Processor with a standard comparator (e.g. std::less) like so:
Processor<std::less> processor1;
Processor<std::greater> processor2;
However it is not so easy to instantiate with SoftOrder as the compiler correctly complains about the missing second template argument:
Processor<SoftOrder<std::less> > processor3; // <-- Fails to compile
Current Solutions
I have come up with a few solutions prior to posting this question.
First Solution - Lots of Derived Classes
template <typename T>
struct SoftOrderLessThan : public SoftOrder<std::less, T> {};
template <typename T>
struct SoftOrderGreaterThan : public SoftOrder<std::greater, T> {};
The main drawback of this solution is the need to create a new struct every time a new variant is required, e.g.:
template <typename T>
struct SoftOrderLessThan : public SoftOrder<std::less, T> {}; // Never used after the next line.
Processor<SoftOrderLessThan> processor3;
Second Solution - A very specific bind class
template <template <typename> class Comparator>
struct BindToSoftOrder {
template <typename T>
struct type : public SoftOrder<Comparator, T> {};
};
This is slightly better in that we don't need to create the intermediate classes explicitly:
Processor<BindToSoftOrder<std::less>::type> processor3;
The downside is the requirement of a class specialised for this situation which cannot really be generalised by making SoftOrder a template parameter on BindToSoftOrder as this would make it a template<template<template>>> which is not permitted by the standard.
Third Solution - C++11 template aliases
template <typename T>
using SoftOrderLessThan = SoftOrder<std::less, T>;
Nicer than the first option in that it doesn't require the introduction of new classes, however still requires littering the code with this extra code that is only used in passing onwards to another template class:
template <typename T>
using SoftOrderLessThan = SoftOrder<std::less, T>; // Never used again
Processor<SoftOrderLessThan> processor3;
Finally, the question
Is there a generic way to bind my custom comparator to a specific comparator in the following manner?
Processor<SomeCoolMetaTemplateBind<SoftOrder, std::less>::type> processor3;
I believe if all of the template parameters were simple types I could just do something like Processor<boost::mpl::bind<SoftOrder, std::less> >, but the presence of the template type in the template parameter list prevents this from occurring.
An ideal solution would involve C++03, but am happy to hear C++11 solutions as well.
If it's not possible, I hope at least the question was interesting.
Seems like this would work:
template <
template <template <typename> class,class> class U,
template <typename> class X
>
struct SomeCoolMetaTemplateBind {
template <typename T>
struct type : public U<X,T> {
};
};