Overload template method in template class - c++

I am trying to overload a template method in a template class. But it will only work if I do it inside the class definition.
How do I get the external implementation outside of the class definition?
template<typename B>
class ClassA {
public:
template<typename T>
void foo( T a );
template<>
void foo( std::string a ) { A = 4; }
template<>
void foo( float a );
B A;
};
template<typename B>
template<typename T>
void ClassA<B>::foo( T a ) { A = a; }
template<typename B>
template<>
void ClassA<B>::foo<float>( float a ) { A = a; }
// Compiler error: unable to match function definition to an existing declaration
void foo() {
ClassA<int> a;
a.foo( 1 );
a.foo<std::string>( "kat" );
a.foo<float>( 4.5f );
}

Since the overloads don't have any template parameters, they aren't templates any more.
template<typename B>
class ClassA {
public:
template<typename T>
void foo( T a );
void foo( std::string a ) { A = 4; }
void foo( float a );
B A;
};
In the version with template<>, they are specializations, not overloads. Overloading, not specialization, is probably what you want.

Related

Template member function specialization of a templated class without specifying the class template parameter

What is the correct syntax to specialize a templated member function of a templated class without specifying the class template parameter?
Here is what I mean:
Example #1 (works):
#include <iostream>
struct C1
{
template <class B>
void f(void) const;
};
template <>
void C1::f<int>(void) const { std::cout<<777<<std::endl; }
int main(void)
{
C1 c1; c1.f<int>();
}
Example #2 (works):
#include <iostream>
template <class A>
struct C2
{
template <class B>
void f(void) const;
};
template <>
template <>
void C2<int>::f<int>(void) const { std::cout<<888<<std::endl; }
int main(void)
{
C2<int> c2; c2.f<int>();
return 0;
}
Example #3 (does not compile: "enclosing class templates are not explicitly specialized"):
#include <iostream>
template <class A>
struct C3
{
template <class B>
void f(void) const;
};
struct D { static int g(void){ return 999; } };
template <class A>
template <>
void C3<A>::f<int>(void) const { std::cout<<A::g()+1<<std::endl; }
template <class A>
template <>
void C3<A>::f<char>(void) const { std::cout<<A::g()+2<<std::endl; }
int main(void)
{
C3<D> c3a; c3a.f<int >(); // expect to see 1000
C3<D> c3b; c3b.f<char>(); // expect to see 1001
return 0;
}
How can I make example #3 work?
You can use a technique called tag dispatch and replace the template specialisations by function overloads.
template<typename>
struct Tag {};
template <class A>
struct C3
{
void f_impl(Tag<int>) const;
void f_impl(Tag<char>) const;
template<class B>
void f() const {
f_impl(Tag<B>{});
}
};
struct D { static int g(void){ return 999; } };
template <class A>
void C3<A>::f_impl(Tag<int>) const { std::cout<<A::g()+1<<std::endl; }
template <class A>
void C3<A>::f_impl(Tag<char>) const { std::cout<<A::g()+2<<std::endl; }
Then your call site looks exactly as you want:
C3<D> c3; c3.f<int>(); // expect to see 1000
C3<D> c4; c4.f<char>(); // expect to see 1001
Full example here.

Template as parameter in class

I have header file and in my header file I make a template and I want to use the template just on one function and not force all other functions. Is it possible to get the type before the function like i did in main?
This is an example:
TestTemp.h
// TestTemp.h
#ifndef _TESTTEMP_H_
#define _TESTTEMP_H_
template<class T>
class TestTemp
{
public:
TestTemp();
void SetValue( int obj_i );
int Getalue();
void sum(T b, T a);
private:
int m_Obj;
};
#include "TestTemp.cpp"
#endif
TestTemp.cpp
//TestTemp.cpp
include<TestTemp.h>
TestTemp::TestTemp()
{
}
void TestTemp::SetValue( int obj_i )
{
m_Obj = obj_i ;
}
int TestTemp::GetValue()
{
return m_Obj ;
}
template<class T>
void TestTemp<T>::sum(T b, T a)
{
T c;
c = b + a;
}
main.cpp
//main.cpp
include<TestTemp.h>
void main()
{
TestTemp t;
t.sum<int>(3,4);
}
Have any ideas?
Your TestTemp is a template class already, no need to make sum template function.
TestTemp<int> t;
t.sum(3, 4);
If you really want to make sum function a template function of TestTemp:
template<class T>
class TestTemp
{
public:
//....
template<typename U>
void sum(U b, U a);
private:
int m_Obj;
};
To implement it outside template class:
template<class T>
template<typename U>
void TestTemp<T>::sum(U b, U a)
{
T c;
c = b + a;
}
int main()
{
TestTemp<int> t;
t.sum<int>(3, 4);
}
However, I feel you just need a free template function
template<typename T>
T sum(T a, T b)
{ return a + b; }
// TestTemp.h
#ifndef _TEST_TEMP_H_
#define _TEST_TEMP_H_
class TestTemp
{
public:
TestTemp();
void SetValue( int obj_i );
int Getalue();
template<class T>
void sum(T b, T a);
private:
int m_Obj;
};
TestTemp::TestTemp() {}
void TestTemp::SetValue( int obj_i )
{
m_Obj = obj_i ;
}
int TestTemp::Getalue()
{
return m_Obj ;
}
template<class T>
void TestTemp::sum(T b, T a)
{
T c;
c = b + a;
}
#endif
//main.cpp
#include <TestTemp.h>
int main()
{
TestTemp t;
t.sum<int>(3,4);
return 0;
}
What you need is a normal class which has a template member function.
It's not a god idea to include an cpp file in header file. For template functions, just put it in header file.
You should take a look here. There are many examples.
I think it should work as you expect it if you just remove
template<class T>
from the
#ifndef _TESTTEMP_H_
#define _TESTTEMP_H_
--> template<class T> <--
class TestTemp
block. You don't have to define the whole class as templated when you just want a method to have template parameters.
You just need to define TestTemp as normal class of which "sum" is a template function. Then in your function "main" (i.e. the caller), the template argument will be deduced from the function arguments.
class TestTemp
{
public:
TestTemp();
void SetValue(int obj_i);
int Getalue();
template<class T>
void sum(T b, T a);
private:
int m_Obj;
};
TestTemp::TestTemp() {}
void TestTemp::SetValue(int obj_i)
{
m_Obj = obj_i;
}
int TestTemp::Getalue()
{
return m_Obj;
}
template<class T>
void TestTemp::sum(T b, T a)
{
T c;
c = b + a;
}
//main.cpp
int main()
{
TestTemp t;
t.sum(3, 4);
return 0;
}

avoid constructor duplication in template specialization

Assume I have a base class that stores a reference to some class Bar:
class FooBase
{
public:
FooBase( Bar &ctx ) : _barCtx( ctx ) {};
virtual ~FooBase() {};
// Some other functions
protected:
Bar &_barCtx;
};
What I'd like to do is add a level of inheritance on top of this, where class Foo<T> will add some functionality.
template< typename T >
class Foo : public FooBase
{
public:
Foo( Bar &ctx ) : FooBase( ctx ) {};
bool doSomething( int a );
};
Then, there are some instances of Foo<T> that need to offer a different version of doSomething(), so template specialization is used. The problem is, in each specialized version of Foo<>, I have to re implement the constructor and pass the reference of Bar to the super class. This is basically copy and paste code, which I'd like to avoid.
class Baz;
template<>
class Foo<Baz> : public FooBase
{
public:
Foob( Bar &ctx ) : FooBase( ctx ) {};
bool doSomething( std::string &str, int x, float g );
};
The point of this exercise is to offer a different type of doSomething(), with a different signature. So, without using C++11 (Because I'm stuck on GCC 4.6.3), is there a way to avoid this duplication of code? Or, is there a better way of offering a different doSomething()?
I actually think a SFINAE approach is better, but if that doesn't work for you for some reason, then specializing individual member functions of a class template might work for you. However, you'll have to declare all overloads in the generic template, then provide the definitions as appropriate. This will make sure that you will get link errors if you call the wrong overloads.
The other option is to use CRTP. That approach is shown further below.
Member specialization approach:
#include <string>
class Bar {};
class FooBase
{
public:
FooBase( Bar &ctx ) : _barCtx( ctx ) {};
virtual ~FooBase() {};
protected:
Bar &_barCtx;
};
template< typename T >
class Foo : public FooBase
{
public:
Foo( Bar &ctx ) : FooBase( ctx ) {};
bool doSomething( int a ) { return true; }
// Declared, but not defined.
bool doSomething( std::string &str, int x, float g );
};
class Baz {};
// Declared, but not defined.
template <>
bool
Foo<Baz>::doSomething(int i);
template <>
bool
Foo<Baz>::doSomething(std::string &str, int x, float g) {
return true;
}
int main() {
Bar b;
Foo<int> f1(b);
std::string s;
f1.doSomething(1); // Compiles.
// f1.doSomething(s, 1, 3.14f); // Link error.
Foo<Baz> f2(b);
// f2.doSomething(1); // Link error.
f2.doSomething(s, 1, 3.14f); // Compiles.
}
CRTP approach:
#include <string>
class Bar {};
class Baz {};
template <typename T>
class Spec {
public:
bool doSomething( int a );
};
template <>
class Spec<Baz> {
public:
bool doSomething( std::string &str, int x, float g );
};
class FooBase {
public:
FooBase( Bar &ctx ) : _barCtx( ctx ) {};
virtual ~FooBase() {};
protected:
Bar &_barCtx;
};
template< typename T >
class Foo : public FooBase, public Spec<T> {
public:
Foo( Bar &ctx ) : FooBase( ctx ) {};
};
template <typename T>
bool Spec<T>::doSomething( int a ) {
Foo<T> *fp = static_cast<Foo<T> *>(this);
return true;
}
bool Spec<Baz>::doSomething( std::string &str, int x, float g ) {
Foo<Baz> *fp = static_cast<Foo<Baz> *>(this);
return true;
}
int main() {
Bar b;
std::string s;
Foo<int> f1(b);
f1.doSomething(1);
Foo<Baz> f2(b);
f2.doSomething(s, 1, 3.14f);
}
Instead of specialising Foo, you could supply every overload, and then enable the relevant overloads with SFINAE:
template< typename T >
class Foo : public FooBase
{
public:
Foo( Bar &ctx ) : FooBase( ctx ) {};
template<
typename U = T,
typename = typename std::enable_if<!std::is_same<U, Baz>::value>::type>
bool doSomething( int a )
{
std::cout << "doSomething( int a )\n";
}
template<
typename U = T,
typename = typename std::enable_if<std::is_same<U, Baz>::value>::type>
bool doSomething( std::string &str, int x, float g )
{
std::cout << "doSomething( std::string &str, int x, float g )\n";
}
};
(Since you can't use C++11, replace std::enable_if and std::is_same with boost versions or your own versions.)
This really seems like the wrong place for using template specialization. The templated type is not being used anywhere in the declaration, so it comes off as completely arbitrary.
I would suggest using other techniques
1) Define an abstract base type for your inputs, and have doSomething take in any implementation of that.
bool doSomething(DoSomethingParamsBase* params);
or
2) Use an enumerated MODE param with variadic params following
bool doSomething(MODE mode...);

boost concept check operator() overload

template <typename T, typename C>
class CSVWriter{
template <typename PrinterT>
void write(std::ostream& stream, const PrinterT& printer){
}
};
I want to check whether there exists at least two overloads PrinterT::operator()(T*) and PrinterT::operator()(C*)
PrinterT may or may not inherit from std::unary_function
What concept Checking Classes I need to use here ?
(I am not using C++11)
You can use something like that
#include <iostream>
#include <boost/concept/requires.hpp>
#include <boost/concept/usage.hpp>
template <class Type, class Param>
class has_operator_round_brackets_with_parameter
{
public:
BOOST_CONCEPT_USAGE(has_operator_round_brackets_with_parameter)
{
_t(_p);
}
private:
Type _t;
Param _p;
};
struct X {};
struct Y {};
struct Test1
{
void operator() (X*) const { }
};
struct Test2: public Test1
{
void operator() (X*) const { }
void operator() (Y*) const { }
};
template <class T, class C>
struct CSVWriter
{
template <class PrinterT>
BOOST_CONCEPT_REQUIRES(
((has_operator_round_brackets_with_parameter<PrinterT, T*>))
((has_operator_round_brackets_with_parameter<PrinterT, C*>)),
(void)) write(std::ostream& stream, const PrinterT& printer)
{
}
};
int main()
{
CSVWriter<X, Y> w;
// w.write<Test1>(std::cout, Test1()); // FAIL
w.write<Test2>(std::cout, Test2()); // OK
return 0;
}

Compile-Time Polymorphism for Data Members

In the following code, initialize() illustrates a method based on compile-time polymorphism. The version of initialize() compiled depends on int2type<true> and int2type<false>, only one of which will be true for a given template parameter T.
It just so happens that data member T* m_datum; will work for both int2type<true> and int2type<false>.
Now, I want to change the int2type<false> version to std::vector<T> m_datum;, so my question is, how do I modify my code so that the data member m_datum is polymorphic on int2type<>?
Note: please ignore the rationale behind the code below - instead, I would like to focus on the mechanics of achieving compile-time polymorphism for data members.
#include <type_traits>
#include <stdlib.h>
using namespace std;
template <bool n>
struct int2type
{
enum { value = n };
};
template< typename T >
struct is_trivially_copyable
{
static const bool value = std::is_standard_layout<T>::value;
};
template<class T>
class Foo
{
public:
Foo( size_t n ) : m_nr( n )
{
initialize( int2type<is_trivially_copyable<T>::value>() );
}
~Foo() { }
private:
void initialize( int2type<true> )
{
m_datum = (T*) calloc( sizeof(T), m_nr );
}
void initialize( int2type<false> )
{
m_datum = new T[m_nr];
}
private:
size_t m_nr;
T* m_datum; // ok for int2type<true>
// vector<T> m_datum; // want to change to this for int2type<false>
};
class Bar
{
public:
Bar() { }
virtual ~Bar() { }
};
int main(int argc, char** argv)
{
Foo<int> foo_trivial( 5 );
Foo<Bar> foo_nontrivial( 10 );
return 0;
}
C++11 solution, based on Nawaz's recommendations
#include <type_traits>
#include <vector>
#include <stdlib.h>
using namespace std;
template< typename T >
struct is_trivially_copyable
{
static const bool value = std::is_standard_layout<T>::value;
};
template<class T>
class Foo
{
private:
static const bool what = is_trivially_copyable<T>::value;
typedef typename std::conditional<what,T*,std::vector<T>>::type type;
public:
Foo( size_t n ) : m_nr( n )
{
initialize( m_datum );
}
~Foo() { }
private:
void initialize( T* dummy )
{
m_datum = (T*) calloc( sizeof(T), m_nr );
}
void initialize( std::vector<T>& dummy )
{
m_datum.resize( m_nr );
}
private:
size_t m_nr;
type m_datum;
};
class Bar
{
public:
Bar() { }
virtual ~Bar() { }
};
int main(int argc, char** argv)
{
Foo<int> foo_trivial( 5 );
Foo<Bar> foo_nontrivial( 10 );
return 0;
}
C++11 Solution
Use std::conditional as:
#include <type_traits>
template<class T>
class Foo
{
//some info we can use throughout the class
static const bool what = is_trivially_copyable<T>::value;
typedef typename std::conditional<what, T*, std::vector<T>>::type data_type;
//data members
data_type m_data; //this is what you need!
}
C++03 Solution
You can write a metafunction and partially specialize this as follows:
template<class T>
class Foo
{
//primary template
template<bool b, typename T>
struct get { typedef T* type; };
//partial specialization
template<typename T>
struct get<false, T> { typedef std::vector<T> type; };
//some info we can use throughout the class
static const bool what = is_trivially_copyable<T>::value;
typedef typename get<what, T>::type data_type;
//data members
data_type m_data; //this is what you need!
};
So when what is true, data_type will turn out to be T*, or else it will be std::vector<T>, as desired.
In either case, you don't need int2type class template. Just remove that from your code. You can write cleaner code, without it.
How about:
// Generic
template <typename T, typename Arg>
struct datum_type_dispatch {};
// Specialization for Arg = int2type<true>
template <typename T>
struct datum_type_dispatch<T, int2type<true> >
{
typedef T* type;
};
// Specialization for Arg = int2type<false>
template <typename T>
struct datum_type_dispatch<T, int2type<false> >
{
typedef std::vector<T> type;
};
template <typename T>
class Foo
{
// ...
private:
// Get the datum type based on int2type<...>
typedef typename datum_type_dispatch<T, int2type<is_trivially_copyable<T>::value> >::type datum_type;
datum_type m_datum;
};