I want to specialize following member function:
class foo {
template<typename T>
T get() const;
};
To other class bar that depends on templates as well.
For example, I would like bar to be std::pair with some template parameters, something like that:
template<>
std::pair<T1,T2> foo::get() const
{
T1 x=...;
T2 y=...;
return std::pair<T1,T2>(x,y);
}
Where T1 and T2 are templates as well. How can this be done? As far as I know it should be
possible.
So now I can call:
some_foo.get<std::pair<int,double> >();
The full/final answer:
template<typename T> struct traits;
class foo {
template<typename T>
T get() const
{
return traits<T>::get(*this);
}
};
template<typename T>
struct traits {
static T get(foo &f)
{
return f.get<T>();
}
};
template<typename T1,typename T2>
struct traits<std::pair<T1,T2> > {
static std::pair<T1,T2> get(foo &f)
{
T1 x=...;
T2 y=...;
return std::make_pair(x,y);
}
};
You can't partially specialize function templates, sorry but those are the rules. You can do something like:
class foo {
...
};
template<typename T>
struct getter {
static T get(const foo& some_foo);
};
template<typename T1, typename T2>
struct getter< std::pair<T1, T2> > {
static std::pair<T1, T2> get(const foo& some_foo) {
T1 t1 = ...;
T2 t2 = ...;
return std::make_pair(t1, t2);
};
and then call it like
getter<std::pair<int, double> >::get(some_foo);
though. You may have to do some messing around with friendship or visibility if get really needed to be a member function.
To elaborate on sbi's suggestion:
class foo {
...
template<typename T>
T get() const;
};
template<typename T>
T foo::get() const
{
return getter<T>::get(*this);
/* ^-- specialization happens here */
}
And now you're back to being able to say
std::pair<int,double> p = some_foo.get<std::pair<int, double> >();
You need to overload your member function for pair, like in
template <T, V> std::pair<T, V> foo::get()
In the general case you will need to be able to disambiguate between the various overloads. In the case disambiguation is easy because pair is templated on 2 types while the original member was templated on T only.
If instead you needed a specialization for, e.g., std::vector, that is for a container with a single parameter template, you have to be careful since given it can be confusing for the compiler to understand if you wish to instantiate the template specialization where the template T is std::vector or the specialization for the overload,
template <T> std::<vector <T> foo::get() const
Your proposed syntax cannot work since you are completely specializing the member function,
template <>,
but you are leaving out two unspecified types, T1 and T2.
Related
I was going through the template Aliases from Tour of C++. I couldn't understand the below code and how to use it?
template<typename T>
class Vector {
public:
using value_type = T;
}
Here he is using the value_type as type alias for typename 'T', Why can't we just use the typename T, since we can pass any type to template(i.e. class Vector). What is the need to have alias for template?
template<typename C>
using Value_type = typename C::value_type;
Here how is value_type in the scope of C, i.e. how can we reference value_type with type 'C', since it is inside class "vector"?
does 'value_type' here mean its a Vector?
and 'Value_type' mean int::Vector or string::Vector etc..?
template<typename Container>
void algo(Container &c)
{
Vector<Value_type<Container>> vec;
}
How are these three pieces linked?
Why a member alias?
Consider you use an instantiation of Vector in some other generic code:
template <typename U>
void foo(const U& u);
Vector<int> v;
foo(v);
Then inside foo we would need to go through some hoops to find out that T is int. foo only knows about U which is Vector<int>. If Vector<int> has a value_type alias then it is much simpler to access that:
template <typename U>
void foo(const U& u) {
using value_type = typename U::value_type;
//...
}
Now foo does not need to care that U::value_type actually was the T parameter to Vector and is also fine with a type that is not an instantiation of a template:
struct OtherVector {
using value_type = int;
};
OtherVector ov;
foo(ov);
No member alias: "some hoops"
Using a member alias is the simple way. For the sake of completeness I want to show the complicated way that lets foo infer T from Vector<T>. You'll have to bear with me...
First, note that function templates cannot be partially specialized. Thats why I introduce a level of indirection:
template <typename U>
struct foo_impl {
void operator()(const U& u) {
std::cout << "Hello \n";
}
};
template <typename U>
void foo(const U& u) { foo_impl<U>{}(u); }
Caller will call foo and in the background we can mess around with foo_impl.
For example we can add a partial specilization for Vector<T> where we can directly have access to T:
template <typename T>
struct foo_impl< Vector<T> > {
void operator()(const Vector<T>& v) {
std::cout << "Hello Vector<T>\n";
if constexpr (std::is_same_v<int,T>) {
std::cout << "T == int\n";
}
}
};
Live Example.
However, consider what that means for foo. The foo above is fine with any type that has a value_type alias. Now we have a rather boring general definition (prints "Hello") and a specialization for Vector<T> (that prints more when T==int). Thats quite a restriction if we want foo to also work with a
template <typename T>
struct Bar {};
What can we do? We can provide a more generic specialization that matches also instantiations of Bar:
template <template<class> class A, class T>
struct foo_impl< A<T> > {
void operator()(const A<T>& v) {
std::cout << "Hello A<T>\n";
if constexpr (std::is_same_v<int,T>) {
std::cout << "T == int\n"; // We know what T is when a Vector<T> is passed !!
}
}
};
Live Example
It is using a template tempalte parameter to match any instantiation of a template with a single template parameter.
Are we fine now? Unfortunately no, because suppose we want to get a "value type" from this:
template <typename A,typename B>
struct Moo {};
Suppose by convention the first parameter, A, is the value type we are looking for. Then we need to add an even more generic specialization:
template <template<class...> class A, typename T,typename... Others>
struct foo_impl< A<T,Others...> > {
void operator()(const A<T,Others...>& v) {
std::cout << "Hello A<T>\n";
if constexpr (std::is_same_v<int,T>) {
std::cout << "T == int\n";
}
}
};
Live Example
This will match an instantiation of a template with any number of type parameters and will detect the first template parameter to be T.
Are we fine yet? Unfortunately: Not at all.
The above does not match a
template <typename A, int x>
struct Omg {};
Because it has a non-type template parameter. We could also fix that, but lets stop here. Requiring that a value type is always the first parameter is too restrictive anyhow.
TL;DR
What we actually want is to make foo work with any type that has an associated "value type". And the simple way to do that is that any type that should be passed to foo to supply a member alias called value_type.
I want to define a template class with 2 template arguments:
A pointer type T*
A pointer to a member function of the underlying type T
Additionally I would like to set a default method for the function argument.
// Do not allow SortedLinkedList<T>
template<typename T, bool (T::* comparisonMethod)(const T&) = &T::lessEqual>
class SortedLinkedList
{
private:
SortedLinkedList();
};
// Allow SortedLinkedList<T*>
template<typename T, bool (T::* comparisonMethod)(const T&)>
class SortedLinkedList<T*>
{
public:
void insert(T* item)
{
// do something with /item->*comparisonMethod)(...))
}
};
This code does not compile, because g++ (4.4.3) can not deduce the underlying type of T*
error: creating pointer to member function of non-class type ‘T*’
Is there a way to deduce the underlying type already in the class declaration? decltype is not available in C++03 and I don't know if it would work at this place.
I've found this answer, but it does not help in this case.
Thanks
The Problem
The reason it fails to compile is that the compiler will check to see that the primary-template is a viable match before it goes on to see if there is any specialization that is a more suitable alternative.
This means that when you try to instantiate SortedLinkedList<A*>, the compiler tries to see if the declaration bool (T::* comparisonMethod)(const T&) = &T::lessEqual, in the primary-template, is well-formed having T = A* - which it obviously isn't (since pointers can't have member-functions).
A Solution
One way to solve this issue is to add a level of indirection, so that both the primary template - and the specialization - yields a well-formed instantiation.
template<class T> struct remove_pointer { typedef T type; };
template<class T> struct remove_pointer<T*> { typedef T type; };
template<class T>
struct comparison_method_helper {
typedef typename remove_pointer<T>::type Tx;
typedef bool (Tx::*type)(Tx const&) const;
};
// primary-template
template<
class T,
typename comparison_method_helper<T>::type = &remove_pointer<T>::type::lessEqual
> class SortedLinkedList;
// specialization
template<typename T, typename comparison_method_helper<T>::type func>
class SortedLinkedList<T*, func> {
public:
void insert (T const& item) {
(item.*func) (T ());
}
};
#include <iostream>
struct A {
bool lessEqual (A const&) const {
std::cerr << "hello world\n";
return false;
}
};
int main () {
SortedLinkedList<A*> ().insert (A()); // outputs 'hello world'
}
This is probably a duplicate, but I just can't find one where the OP clearly has the same problem I'm having.
I have a class, and I'm trying to enable operator- only if the class template parameter is not an unsigned type.
#include <type_traits>
template<class T>
struct A {
typename std::enable_if<!std::is_unsigned<T>::value,A>::type operator-() {return {};}
};
int main() {
A<unsigned> a=a;
}
Unfortunately, this produces a compiler error any time I instantiate it with an unsigned type as shown.
main.cpp:5:29: error: no type named 'type' in 'std::enable_if<false, A<unsigned int> >'; 'enable_if' cannot be used to disable this declaration
typename std::enable_if<!std::is_unsigned<T>::value,A>::type operator-() {return {};}
^~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:9:17: note: in instantiation of template class 'A<unsigned int>' requested here
A<unsigned> a=a;
^
Well, I can clearly see that enable_if is not going to work here. One vaguely similar question mentioned I can use inheritance and template specialization to work around this, but... is there really no better way?
I had the same problem once. Turns out there can't be a substitution failure since the default template argument doesn't depend on a template parameter from the function template. You have to have a template argument defaulted to the enclosing template type, like this:
template<typename U = T,
class = typename std::enable_if<!std::is_unsigned<U>::value, U>::type>
A operator-() { return {}; }
A bit long for a comment: You can also use a free function, even for unary operators.
#include <type_traits>
template<class T>
struct A {
};
template<class T>
typename std::enable_if<!std::is_unsigned<T>::value,A<T>>::type
operator-(A<T>) {return {};}
int main() {
A<signed> b;
-b; // ok
A<unsigned> a;
-a; // error
}
This doesn't introduce a member function template for each class template.
Here's how you can befriend it:
template<class T>
class A {
int m;
public:
A(T p) : m(p) {}
template<class U>
friend
typename std::enable_if<!std::is_unsigned<U>::value,A<U>>::type
operator-(A<U>);
};
template<class T>
typename std::enable_if<!std::is_unsigned<T>::value,A<T>>::type
operator-(A<T> p) {return {p.m};}
int main() {
A<signed> b(42);
-b; // ok
A<unsigned> a(42);
//-a; // error
}
You can (should) forward-declare that function template, though.
One possible way is introducing a dummy template parameter:
template<class T>
struct A {
template<
typename D = int,
typename = typename std::enable_if<!std::is_unsigned<T>::value, D>::type
>
A operator-() {return {};}
};
There is a long way using inheritance:
template <class T>
struct A;
template <class T, bool = std::is_unsigned<T>::value>
struct MinusOperator
{
A<T> operator-()
{
A<T>* thisA = static_cast<A<T>*>(this);
// use thisA instead of this to get access to members of A<T>
}
};
template <class T>
struct MinusOperator<T, true> {};
template <class T>
struct A : MinusOperator<T>
{
friend struct MinusOperator<T>;
};
I have a C++ templated class
// Definition
template <typename T>
class MyCLass {
public:
typedef typename T::S MyS; // <-- This is a dependent type from the template one
MyS operator()(const MyS& x);
};
// Implementation
template <typename T>
MyCLass<T>::MyS MyClass<T>::operator()(const MyClass<T>::MyS& x) {...}
What I want is that overloaded operator operator() behaves differently when MyS is double.
I thought about specialization, but how to do in this case considering that the specialization should act on a type-dependent type? Thankyou
You could forward the work to some private overloaded function:
template <typename T>
class MyCLass {
public:
typedef typename T::S MyS;
MyS operator()(const MyS& x) { return operator_impl(x); }
private:
template<typename U>
U operator_impl(const U& x);
double operator_impl(double x);
};
You can solve this by introducing an extra default parameter:
template <typename T, typename Usual = typename T::S>
class MyClass { ... };
Then you can specialize using a double:
template <typename T>
class MyClass<T, double> { ... }
I would to make a template match only for T=std::vector<T2> arguments (T2 is an arbitrary type). I can use boost::enable_if in template arguments. How do I test whether a type T is a std::vector?
I could include T::iterator in my template so that non-container types would lead to substitution failure and would not be considered (SFINAE). This way though, any containers which define T::iterator would match, not only std::vector<T2>.
You probably don't need enable_if, a simple partial specialization should be enough:
template <typename T>
struct Type { ... };
// partial specialization for std::vector
template <typename T>
struct Type< std::vector< T > > { ... };
If you are dealing with a function template, you can simply provide an overload:
template <typename T>
void foo( const T & t ) { ... }
// overload for std::vector
template <typename T>
void foo( const std::vector< T > & vec ) { ... }
How about this:
template <class T2>
struct is_std_vector { static const bool value=false; };
template <class T2>
struct is_std_vector<std::vector<T2> > { static const bool value=true; };
Use together with enable_if!
Why do you even want to use a template for that? Can't you just write a plain function?
Anyhow, it's possible:
template<class T
,class=typename std::enable_if<(
std::is_same<T,std::vector<int>>::value
)>::type
>
void foo(T const& vec)
(this is C++11: default template arguments for function templates + type_traits + >> not being a shift operator)
Edit: I just realized that T2 in your question is probably not some fixed type but a placeholder to allow many kinds of vectors. In that case, I recommend accepting Luc's answer.
Viele Grüße nach Österreich! :-)