How to change template instantiate order? - c++

I want to change the instantiate order of the overload templates. My code are as follow:
#include <iostream>
#include <vector>
using namespace std;
template<typename T>
struct Base
{
};
template<typename T>
struct Derived:Base<T>
{
};
//template 1
template<typename T1>
void f(Base<T1>& a){
cout<<"in 1\n";
}
//template 2
template<typename T2>
void f(T2 b){
cout<<"in 2\n";
}
int main(){
Derived<int> v1;
f(v1);
}
The compiler will chose template 2 as default, but I want it to chose template 1.

With custom traits
template <typename T> std::true_type derive_from_base_impl(const Base<T>*);
std::false_type derive_from_base_impl(...);
template <typename T>
using derive_from_base = decltype(derive_from_base_impl(std::declval<T*>()));
static_assert(!derive_from_base<int>::value, "");
static_assert(derive_from_base<Derived<int>>::value, "");
And SFINAE, you may do
template<typename T>
void f(Base<T>& a) { std::cout << "in 1\n"; }
template<typename T>
std::enable_if_t<!derive_from_base<T>::value>
f(T b) { std::cout << "in 2\n"; }
Demo

The right term for this is overload resolution preferences, and second overload is chosen because it is a better match. It appeared to be more challenging than I expected to put together a code which would make sure proper overload was selected. Here it is:
#include <type_traits>
#include <iostream>
template<typename T>
struct Base { };
template<typename T>
struct Derived:Base<T> { };
template <class T>
struct template_argument { using type = void*; };
template <template <class > class T, class ARG>
struct template_argument<T<ARG> > {
using type = ARG;
};
template <class T>
using template_argument_t = typename template_argument<T>::type;
template<typename T1>
void f(Base<T1>& ){
std::cout << "Base-expecting f called\n";
}
template<class T>
void f(T, std::enable_if_t<!std::is_base_of<Base<template_argument_t<T> >, T>::value>* = nullptr ) {
std::cout << "Generic f was called.\n";
}
template <class T>
struct Z { };
int main(){
Derived<int> v1;
f(v1);
f(int() );
f(Z<int>() );
}
Output:
Base-expecting f called
Generic f was called.
Generic f was called.

The answer is quite simple, all you have to do is prevent the second template to be instantiated for a certain class, which can be done quickly using std::enable_if_t from the type_traits header:
Template 2 becomes this, and Template 1 remains unchanged
//template 2
template<typename T2, std::enable_if_t<!std::is_base_of<Base<T2>, T2>::value>>
void f(T2 b) {
cout << "in 2\n";
}

Provide an argument that has a better match:
int main(){
Derived<int> v1;
f(v1); // in 2
f((Base<int>&)v1); // in 1
}
In this case
f(v1) will resolve to f<Base<int>>(v1)
and f((Base<int>&)v1) to f<int>(v1)

Related

How to tell if template type is an instance of a non-variadic template class?

This question is awful similar to How to tell if template type is an instance of a template class?
I would like to detect if a template parameter is from one particular template class that has no variadic template arguments.
template<class U, class S>
struct A{};
template<class T>
struct B {
B() {
if constexpr (T == A) {
// T is a template instantiation of `A`.
} else {
}
}
};
I can't change A's definition. I can change B's definition to have additional template parameters.
How do I implement (T == A) given the restriction of not knowing A's U and S?
I would go for a partial specialization here.
#include <iostream>
template<class U, class S>
struct A{};
template<class T>
struct B {
B() {
std::cout << "None-A implementation\n";
}
};
template<class U, class S>
struct B<A<U, S>> {
B() {
std::cout << "A implementation\n";
}
};
int main() {
B<int> b1;
B<A<int, int>> b2;
}
You have the option of leaving the default-case without an implementation.
Or you can have a fallback implementation for any none-A classes like here.
If the partial specialization forces too much code duplication you can also extract the detection part to it's own template variable like this.
#include <iostream>
template<class U, class S>
struct A{};
template <class T>
constexpr bool is_A_instatiation = false;
template <class U, class S>
constexpr bool is_A_instatiation<A<U, S>> = true;
template<class T>
struct B {
B() {
if constexpr (is_A_instatiation<T>) {
std::cout << "A instatiation!\n";
} else {
std::cout << "none-A instatiation!\n";
}
}
};
int main() {
B<int> b1;
B<A<int, int>> b2;
}
The easiest way is:
template<class T>
struct B{/*default implementation*/};
template<class U,class S>
struct B<A<U,S>>{/*Specified implementation*/};
A<T,U>: you already know it and search key
B<...>: variadic types which may include A<T,U> - known type
And you want to search A<T,U> in B<...>
template <typename T, typename U>
struct A {};
template <typename T, typename U, typename ...Ts>
struct B {
static constexpr bool value = ((std::is_same_v< A<T, U>, Ts> || ... ));
};
int main() {
std::cout << std::boolalpha <<
B<int,float, int, int, float, A<int,float>>::value << '\n'<<
B<int,float, int, int, float>::value <<std::endl;
}

why C++ template type matching does not match to base class refrence, how can I make it match to base class refrence?

Here is my C++ program code
#include <iostream>
#include <memory>
using namespace std;
template <typename T>
struct A { T x; };
template <typename T>
struct B:A<T> { };
template <typename T>
void func(const A<T>& t) {
cout<<"2"<<endl;
}
template <typename T>
void func(const T& t) {
cout<<"1"<<endl;
}
int main() {
B<int> b;
func(b);
}
and it prints 1. But what I expect is the function call prints 2. Why B<int>b matches to const T& instead of const A<T>&. And how can I make it to match to const A<T>&?
Solution 1
You could use std::enable_if and templated template parameters to get a better match for the function, like:
#include <iostream>
#include <memory>
#include <type_traits>
using namespace std;
template <typename T>
struct A { T x; };
template <typename T>
struct B:A<T> { };
template <template <typename...> typename T, typename ...Args, typename = std::enable_if_t<std::is_base_of_v<A<Args...>, T<Args...>>>>
void func(const T<Args...>& t) {
cout<<"2"<<endl;
}
template <typename T>
void func(const T& t) {
cout<<"1"<<endl;
}
int main() {
B<int> b;
func(b);
func(5);
}
However, this works only if A takes exactly the same template parameters as T. So if your B changes to ex.
template <typename T, typename U>
struct B : A<T> {}
this won't work anymore.
Solution 2
Based on Yakk's answer you can create a type trait that is more generic. This solution has no restrictions to its template parameters, like solution 1 does.
namespace detail
{
template <template <typename...> typename Base>
struct template_base_detector
{
template <typename... Args>
constexpr std::true_type operator()(Base<Args...>*);
constexpr std::false_type operator()(...);
};
}
template <template <typename...> typename Base, typename T>
struct is_template_base_of
: decltype(std::declval<detail::template_base_detector<Base>>()((T*)nullptr)) {};
// since C++ 14
template <template <typename...> typename Base, typename T>
constexpr bool is_template_base_of_v = is_template_base_of<Base, T>::value;
Depending on your c++ version, you can use different approaches to utilize this trait.
C++ 17
Probably the most compact solution. Since C++ 17 constexpr if statements are allowed, which allows us to define just a single func:
template <typename T>
void func(const T& t)
{
if constexpr (is_template_base_of_v<A, T>)
cout << 2 << endl;
else
cout << 1 << endl;
}
C++ 11 and 14
We have to fall back to tag dispatch:
namespace detail
{
template <typename T>
void func(std::true_type, const T& t)
{
std::cout << 2 << endl;
}
template <typename T>
void func(std::false_type, const T& t)
{
std::cout << 1 << endl;
}
}
template <typename T>
void func(const T& t)
{
detail::func(is_template_base_of<A, T>{}, t);
}
Tag dispatching.
First, we write a trait to detect if something has a template as a base:
namespace details {
template<template<class...>class Z>
struct htb {
template<class...Ts>
constexpr std::true_type operator()(Z<Ts...>*){return {};}
constexpr std::false_type operator()(...){return {};}
};
}
template<template<class...>class Z, class X>
constexpr inline auto has_template_base = details::htb<Z>{}((X*)nullptr);
we can now use our new trait to tag dispatch:
namespace details{
template <typename T>
void func(std::true_type,const A<T>& t) {
std::cout<<"2"<<std::endl;
}
template <class T>
void func(std::false_type,const T& t) {
std::cout<<"1"<<std::endl;
}
}
template <typename T>
void func(const T& t) {
details::func(has_template_base<A,T>,t);
}
Live example.

One template specialization for PODs, one for class hierarchy and error in other cases?

I'm trying to create a template which would work one way for all fundamental types, other way for all classes deriving from A and fail for everything else. Reading about SFINAE, I created such thing:
struct A {};
struct B : A
{
int a;
};
template <typename T, typename = typename std::enable_if<std::is_base_of<A, T>::value>::type>
void foo(const T& derived)
{
std::cout << "stuff with derived";
}
template <typename T, typename = typename std::enable_if<std::is_fundamental<T>::value>::type>
void foo(const T& pod)
{
std::cout << "stuff with fundamental";
}
int main()
{
foo(7);
B instance;
foo(instance);
}
From what I understood, matching template types for 7 (int) fails for first case and works for second, and derived class works for first. What mistake am I doing?
Try this:
#include <iostream>
struct A {};
struct B : A
{
int a;
};
template <typename T>
typename std::enable_if<std::is_base_of<A, T>::value, void>::type foo(const T& derived)
{
std::cout << "stuff with derived";
}
template <typename T>
typename std::enable_if<std::is_fundamental<T>::value, void>::type foo(const T& pod)
{
std::cout << "stuff with fundamental";
}
int main()
{
foo(7);
B instance;
foo(instance);
}
The second parameter of enable_if<> is the return type.

Template function specialization for template class

Is it possible to write something like this in C++11/14?
#include <iostream>
#include <vector>
template <typename T>
T Get();
template <typename T>
struct Data {
std::vector<T> data;
};
template <>
template <typename T>
Data<T> Get<Data<T>>() {
return Data<T>{{T{}, T{}}};
}
template <>
template <typename T>
std::vector<T> Get<std::vector<T>>() {
return std::vector<T>(3);
}
int main() {
std::cout << Get<Data<int>>().data.size() << std::endl; // expected output is 2
std::cout << Get<std::vector<int>>().size() << std::endl; // expected output is 3
return 0;
}
Overloading won't help in this case, since call to Get<...>() will be ambiguious (see):
template <typename T>
Data<T> Get() {
return Data<T>{{T{}, T{}}};
}
template <typename T>
std::vector<T> Get() {
return std::vector<T>(3);
}
Any direction on how to overcome this are welcome.
There is workaround, that gives you something like this: do not specialize - overload:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template <typename T>
size_t Get(const T& data)
{
return 444;
}
template <typename T>
struct Data
{
std::vector<T> data;
};
template <typename T>
size_t Get(const Data<T>& data) {
return data.data.size();
}
int main() {
std::cout << Get<>(0) << std::endl; // expected output is 444
std::cout << Get<>(Data<int>{}) << std::endl; // expected output is 0
return 0;
}
Output:
444
0
Note, that size_t Get(const Data<T>& data) is not a specialization - it is completely "different" Get(), that is called for argument of type Data<T> for any T.
Here you can see working sample.
EDIT
I see you changed your question completely. However, I will still try to answer it. There is a standard workaround for lack of partial function specialization - using delegation to structs/classes.
Here is what you need:
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
struct GetImpl;
template <typename T>
struct Data {
std::vector<T> data;
};
template <typename T>
struct GetImpl< Data<T> >
{
static Data<T> Get() {
return Data<T>{ {T{}, T{}} };
};
};
template <typename T>
struct GetImpl< std::vector<T> >
{
static std::vector<T> Get() {
return std::vector<T>(3);
};
};
int main() {
std::cout << GetImpl< Data<int> >::Get().data.size() << std::endl; // expected output is 2
std::cout << GetImpl< std::vector<int> >::Get().size() << std::endl; // expected output is 3
return 0;
}
Output:
2
3
Working sample can be found here.
If you don't like the syntax, you can make it a little bit shorter, by changing static function Get() to function call operator:
template <typename T>
struct Get< Data<T> >
{
Data<T> operator()() {
return Data<T>{ {T{}, T{}} };
};
};
template <typename T>
struct Get< std::vector<T> >
{
std::vector<T> operator()() {
return std::vector<T>(3);
};
};
And then:
Get< Data<int> >()().data.size();
Get< std::vector<int> >()().size();
You have only two extra characters - (). This is the shortest solution I can think of.
As Columbo mentioned in his comment, you should apply the standard workaround for lack of partial specialization support for functions: delegation to a partially specialized class:
template <typename T>
struct GetImpl;
template <typename T>
T Get() { return GetImpl<T>::Do(); }
and now use partial specialization on struct GetImpl<T> { static T Do(); } instead of Get<T>()
But it would be impossible for compiler to distinguish Get<Data<int>> from Get<Data<Data<int>>>.
It's not impossible. If that's something you need to do, we can add separate overloads:
template <typename T>
size_t Get(const Data<T>& data);
template <typename T>
size_t Get(const Data<Data<T>>& data); // preferred for Data<Data<int>>
Or if what you want is to only overload for the non-nested case, we can add a type trait and use SFINAE:
template <typename T> struct is_data : std::false_type { };
template <typename T> struct is_data<Data<T>> : std::true_type { };
template <typename T>
enable_if_t<!is_data<T>::value, size_t>
Get(const Data<T>& data);
That way, the call with Data<Data<int>> would call the generic Get(const T&). Or, if you want that case to not compile at all:
template <typename T>
size_t Get(const Data<T>& data) {
static_assert(!is_data<T>::value, "disallowed");
...
}
So overloading gives you lots of options. Specialization gives you none, since it's disallowed anyway.
Following delegation to the struct's way you can implement more general approach: you can use structs to check the container type and inner type like this:
#include <iostream>
#include <vector>
template <typename T>
struct Data {
std::vector<T> data;
};
template <template <typename...> class Container, typename>
struct get_inner;
template <template <typename...> class Container, typename T>
struct get_inner<Container, Container<T>>
{
typedef T type;
};
template <typename T, typename U = typename get_inner<Data, T>::type>
Data<U> Get() {
return Data<U>{ {U{}, U{}} };
}
template <typename T, typename U = typename get_inner<std::vector, T>::type>
std::vector<U> Get() {
return std::vector<U>(3);
}
int main() {
std::cout << Get<Data<int>>().data.size() << std::endl; // expected output is 2
std::cout << Get<std::vector<int>>().size() << std::endl; // expected output is 3
return 0;
}
http://coliru.stacked-crooked.com/a/90b55767911eff0e

Can be template function within class template specialized outside of the class template?

Can be template function within class template specialized outside of the class template?
What is the syntax for it?
Following code gives unable to match function definition to an existing declaration in MSVC2010
#include <iostream>
template <typename T>
struct Test
{
template <typename S>
void test(const S & t);
//this works
//template<> void test(const double & t) { std::cout << t << "D \n"; }
T member;
};
//this doesn't work
template <typename T>
template <>
void Test<T>::test(const double & t)
{
std::cout << t << "D \n";
}
int main()
{
Test<int> t;
t.test(7.0);
}
edit
I can use overload as suggested in answers, because I use it little differently, here is how:
#include <iostream>
template <typename T>
struct Test
{
template <typename S>
void test() { std::cout << "Any type \n"; }
template <>
void test<double>() { std::cout << "Double! \n"; }
T member;
};
int main()
{
Test<int> t1;
Test<int> t2;
t1.test<float>();
t2.test<double>();
}
and I want specialization for double outside of the struct.
Why I use it like this you ask? In real scenario I have built factory class which is used like:
Factory<SomePolicy> f;
f.create<MyType>(arg1, arg2, ...)
and I need specialization of create for specific type which won't pollute header file.
As far as I know you can't. But you can just overload your test function like this:
template <typename T>
struct Test
{
template <typename S>
void test(const S & t);
void test(const double &); // <-- Add this
T member;
};
template <typename T>
// template<> // <-- Remove this
void Test<T>::test(const double & t)
{
std::cout << t << "D \n";
}
Which should be totally equivalent to what you want to do.
I do not believe you can specialize the inner template without specializing the outer. You could, however, use partial specialization:
Edit: It appears that only classes can be partially specialized. Again, I haven't tested it. You can find more here
template <typename T, typename S>
struct Test
{
void test(const S &s);
};
template <typename T>
struct Test<T, float>
{
void test (const float &s)
{
<<do something>>
}
}