I am constructing a library that makes use of expression templates, where I make heavily use of templated functions in classes. All my code is running and recently I decided to make the main class templated to allow for using it on data of different kinds. However, I can no longer specialize my functions. How do I solve this? I have attached a small test program that shows the problem.
My previous Animal class was not templated and then this code works fine.
#include<iostream>
#include<vector>
// Example templated class with templated function
template<class T>
class Animals
{
public:
template<class X>
void printFood(const X& x) const { std::cout << "We eat " << x << "!" << std::endl; }
private:
std::vector<T> animals;
};
// How do I specialize?
template<class T> template<>
void Animals<T>::printFood(const unsigned int& x) const { std::cout << "We don't want to eat " << x << "!" << std::endl; }
// Main loop;
int main()
{
Animals<double> doubleAnimals;
const int banana = 42;
doubleAnimals.printFood(banana);
const unsigned int apple = 666;
doubleAnimals.printFood(apple);
return 0;
}
This simply isn't possible
[temp.expl.spec]
16 In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well.
You should specialize your class first. Then specialize function:
template<> template<>
void Animals<double>::printFood(const unsigned int& x) const { std::cout << "We don't want to eat " << x << "!" << std::endl; }
You can't partially specialize template members of non-specialized template class. This is consistent with prohibiting partial specialization of template functions (think of template class as the member function's first parameter). Use overloading instead:
template<class T>
class Animals
{
public:
template<class X>
void printFood(const X& x) const { std::cout << "We eat " << x << "!" << std::endl; }
void printFood(const unsigned int& x) const { std::cout << "We don't want to eat " << x << "!" << std::endl; }
private:
std::vector<T> animals;
};
Related
Short question;
I don't get why this syntax exists:
template <int in>
void test(){
std::cout << in << std::endl;
}
int main(){
test<5>();
return 0;
}
When you can do the same without templates:
void test(test in){
std::cout << in << std::endl;
}
int main(){
test(5);
return 0;
}
How would you do this without templates?
template<std::size_t n> void f() {
char buf[n];
}
Besides, passing values as arguments requires extra arguments, extra run-time overhead, not necessarily needed when you know a value is actually a compile-time constant. With classes, it would require an extra member, and an extra construction argument for a class which might otherwise be empty and trivial.
What you have shown is not partial specialization.
Here an example of specialization (in this case full specialization):
#include <iostream>
template <int in, int in2>
void test_template(){
std::cout << in << std::endl;
}
template <>
void test_template<1>(){
std::cout << "one" << std::endl;
}
template <>
void test_template<2>(){
std::cout << "two" << std::endl;
}
int main()
{
test_template<1>();
test_template<2>();
test_template<3>();
test_template<4>();
}
And it is useful to handle certain template parameters in a special way. (Partial specialization, is if you have multiple template arguments and specialize all except one of them)
Regarding your example, the use-case you have shown does not illustrate where it can be useful, as it indeed does not make much a difference to use a regular function there.
But if you look at functions like std::make_shared or std::make_pair there is no way how you could solve that without using templates:
template< class T1, class T2 >
std::pair<T1,T2> make_pair(T1 t, T2 u) {
return std::pair<T1,T2>(t,u);
}
They are not "the same".
The two versions of test are very different. I rename them to avoid confusion and merely list some differences:
template <int in>
void test_template(){
std::cout << in << std::endl;
}
void test_fun(test in){
std::cout << in << std::endl;
}
test_template is a template. It is not a function. For example it is not possible to get a pointer to test_template:
auto f_ptr1 = &test_template; // doesn't make sense
auto f_ptr2 = &test_fun; // OK
The template parameter has to be known at compile time:
int x;
std::cin >> x;
test_template<x>(); // error: x must be known at compile time
test_fun(x); // OK
On the other hand, once you did instantiate the template you get a function with no parameters:
auto f = &test_template<5>;
f();
auto g = &test_template<6>;
g();
Similar you can only do with test_fun when you wrap it into another function (ie overhead).
... and more.
PS: There is no partial specialization in your code.
In the following code yields (LiveExample):
Class template pointer
Class template pointer
Template pointer
Template array with size 10
#include <iostream>
#include <utility>
#include <type_traits>
template <class TVar>
class CVar
{
public:
void classTemplate(TVar *) const
{
std::cout << "Class template pointer\n";
}
template<unsigned sz>
void classTemplate(TVar(&)[sz]) const
{
std::cout << "Class template array with size " << sz << "\n";
}
};
template<typename T>
void regTemplate(T)
{
std::cout << "Template pointer\n";
}
template<typename T, unsigned sz> void regTemplate(T(&)[sz])
{
std::cout << "Template array with size " << sz << "\n";
}
int main()
{
unsigned int test[10] = {};
CVar<unsigned> *cFoo = new CVar<unsigned>();
cFoo->classTemplate(&test[0]);
cFoo->classTemplate(test);
regTemplate(&test[0]);
regTemplate(test);
}
Why when I overload the template in the class, it cannot resolve the desired functionality - that is, cFoo->classTemplate(test); is called, then the response will be Class template array with size 10?
How do I achieve my desired result in 1 without changing cFoo->classTemplate(test);? Note that void CVar<TVar>::classTemplate(TVar(&)[sz]) const may change if needed
Other things equal, overload resolution prefers non-templates over templates. In classTemplate case, one overload is a function template while the other is a non-template member function.
In regTemplate case, both are function templates: the one taking an array is chosen because it's more specialized. Indeed, if you change the first overload to take T*, the call becomes ambiguous.
Is there a way to code a single template function able to run on different members of a given struct ?
A wrong example would look like :
struct Foo
{
int a, b;
}
template <MEMBER x> //which does not exist
cout_member(Foo foo)
{
cout << foo.x << endl;
}
int main()
{
Foo foo;
cout_member<a>(foo);
cout_member<b>(foo);
return 0;
}
I imagined an answer based on a switch, but I then wondered if this switch would be tested on run-time (what I would like to avoid) or on compile-time ?
As long as you want to pick up a data member from a set of data members having the same type, you can use a pointer to data member:
template <int Foo::*M>
void cout_member(Foo foo)
{
std::cout << (foo.*M) << std::endl;
}
And use it as:
cout_member<&Foo::a>(foo);
If you want to indicate also the type, you can do this:
template <typename T, T Foo::*M>
void cout_member(Foo foo)
{
std::cout << (foo.*M) << std::endl;
}
And use it as:
cout_member<int, &Foo::a>(foo);
Just out of curiosity, the second snippet would be even simpler in C++17:
template <auto M>
void cout_member(Foo foo)
{
std::cout << (foo.*M) << std::endl;
}
See it up and running on wandbox;
You can leverage std::mem_fn so you don't even have to care: (untested)
template < typename Fun, typename ... Params >
void print(Fun f, Params && ... p) { std::cout << f(std::forward<Params>(p)...) << "\n"; }
print(std::mem_fn(&Obj::fun), Obj());
Since you're using streams you probably don't care...but this should add little to zero overhead from just writing cout << obj.fun().
Edit: mem_fn works on data members too. Creates a callable that returns a reference to the value that you can then use: int x = mem_fn(&pair<int,char>::first)(my_pair);
I am trying to get a better understanding of std::enable_if in C++11 and have been trying to write a minimal example: a class A with a member function void foo() that has different implementations based on the type T from the class template.
The below code gives the desired result, but I am not understanding it fully yet. Why does version V2 work, but not V1? Why is the "redundant" type U required?
#include <iostream>
#include <type_traits>
template <typename T>
class A {
public:
A(T x) : a_(x) {}
// Enable this function if T == int
/* V1 */ // template < typename std::enable_if<std::is_same<T,int>::value,int>::type = 0>
/* V2 */ template <typename U=T, typename std::enable_if<std::is_same<U,int>::value,int>::type = 0>
void foo() { std::cout << "\nINT: " << a_ << "\n"; }
// Enable this function if T == double
template <typename U=T, typename std::enable_if<std::is_same<U,double>::value,int>::type = 0>
void foo() { std::cout << "\nDOUBLE: " << a_ << "\n"; }
private:
T a_;
};
int main() {
A<int> aInt(1); aInt.foo();
A<double> aDouble(3.14); aDouble.foo();
return 0;
}
Is there a better way to achieve the desired result, i.e. for having different implementations of a void foo() function based on a class template parameter?
I know this wont fully answer your question, but it might give you some more ideas and understanding of how you can use std::enable_if.
You could replace your foo member functions with the following and have identical functionality:
template<typename U=T> typename std::enable_if<std::is_same<U,int>::value>::type
foo(){ /* enabled when T is type int */ }
template<typename U=T> typename std::enable_if<std::is_same<U,double>::value>::type
foo(){ /* enabled when T is type double */ }
A while back I gained a pretty good understanding of how enable_if works, but sadly I have forgotten most of its intricacies and just remember the more practical ways to use it.
As for the first question: why V1 doesn't work? SFINAE applies only in overload resolution - V1 however causes error at the point where type A is instantiated, well before foo() overload resolution.
I suppose there are lot's of possible implementations - which is the most appropriate depends on an actual case in question. A common approach would be to defer the part of A that's different for different template types to a helper class.
template <typename T>
class A_Helper;
template <>
class A_Helper<int> {
public:
static void foo( int value ){
std::cout << "INT: " << value << std::endl;
}
};
template <>
class A_Helper<double> {
public:
static void foo( double value ){
std::cout << "DOUBLE: " << value << std::endl;
}
};
template <typename T>
class A {
public:
A( T a ) : a_(a)
{}
void foo(){
A_Helper<T>::foo(a_);
}
private:
T a_;
};
The rest of A can be declared only once in a generic way - only the parts that differ are deferred to a helper. There is a lot of possible variations on that - depending on your requirements...
I've seen lots of SO questions about specialization in the context of methods, but not functions belonging to classes. I'm having a hard time translating the knowledge passed on from those questions to my problem here.
I'm mucking around with a class I created in the past to learn and I would like to have a specialization for arithmetic types.
template <typename T>
class Vector3
{
public:
T x;
T y;
T z;
public:
operator std::string() const;
}
This is the specialization I am trying to do:
template<typename T = std::enable_if<std::is_arithmetic<T>::value, T>::type>
inline Vector3<T>::operator std::string() const {
std::stringstream ss;
ss << "NOT NUMBER {" << x << ", " << y << ", " << z << "}";
return ss.str();
}
template<typename T = std::enable_if<!std::is_arithmetic<T>::value, T>::type>
inline Vector3<T>::operator std::string() const {
std::stringstream ss;
ss << "NUMBER {" << x << ", " << y << ", " << z << "}";
return ss.str();
}
However when I try to compile, I get
error C2995: 'Vector3::operator std::string(void) const': function
template has already been defined
When I google this, it is usually cases where people have defined their class/method in the CPP file as well as the header file. As I only do this in the header file, I can only assume the enable_if is not correct. When I look at other examples, they just do specialization on , , but I'd like to use the is_arithmitic way.
What am I doing wrong? Thanks in advance
The default here:
template<typename T = XXX>
inline Vector3<T>::operator std::string() const { ... }
doesn't matter at all, there's no deduction going on at this point, and T is already defined. It's legal, but it's just noise.
Now, you can't partially specialize a member function in a class template either, but we can dispatch on traits:
template <class T>
class Vector3 {
public:
// ...
operator std::string() const {
return as_string(std::is_arithmetic<T>{});
}
private:
std::string as_string(std::true_type ) {
// implementation for arithmetic types
}
std::string as_string(std::false_type ) {
// implementation for non-arithmetic types
}
};
Barry's answer is perfect.
Here is some explanation and suggestions:
http://en.cppreference.com/w/cpp/types/enable_if
"A common mistake is to declare two function templates that differ only in their default template arguments. This is illegal because default template arguments are not part of function template's signature, and declaring two different function templates with the same signature is illegal."