Let's say I have a base class foo and two derived classes A and B. I then have another class bar, which has a data members x, y, z, which can be either A,or, but the types depends on other data members x_type, y_type, and z_type, and those values are not available at compile time. I though about using template data member and defining the type in constructor, where I get the values for the types but apparently that is not possible at least in C++11. So how to proceed?
class foo{
public:
foo(double);
int x_type;
virtual double do_something(double, int) = 0;
};
class A: public foo {
public:
A(double, double);
double do_something(double, int);
private:
double z1;
double z2;
};
class B: public foo {
public:
B(double);
double do_something(double, int);
private:
double w;
};
class bar {
public:
bar();
double do_something2(int);
private:
int x_type;
int y_type;
int x_type;
x; // these are either A or B...
y;
z;
};
And in constructor I would have something like
if(x_type == 1){
x = A(arg1, arg2);
} else {
x = B(arg3);
}
In my real application there can be much higher number of derived classes and data members with unknown types. I was wondering if it is possible to make bar a template class with multiple template parameters, but I am not sure if that is possible either as the parameter type depends on another parameter?
You need to use polymorphism and take advantage of the common base class Foo:
private:
int x_type;
int y_type;
int x_type;
std::unique_ptr<Foo> x; // these are either A or B...
std::unique_ptr<Foo> y;
std::unique_ptr<Foo> z;
};
Then in your constructor you can create x y z from the correct type:
if(x_type == 1){
x.reset(new A(arg1, arg2));
} else {
x.reset(new B(arg3));
}
It is a good practice to move the code that creates the correct Foo instance in a so called "factory" class or function in order to hide the decision making logic and construction specifics (which might be quite complex at times).
If all type that can be used for x, y and z are all derived from a common base class, the base-pointer solution, with std::unique_ptr (+1 for Lyubomir Stankov), is (IMHO) a good solution.
But you asked "if it is possible to make bar a template class with multiple template parameters".
Yes: it's possible. Not really elegant (ever IMHO) but possible.
I propose the following solution for fun but I think that, in a more general case (note that, in my example, A and B are unrelated classes, not more derived from foo), can be useful (I hope so)
#include <tuple>
#include <string>
#include <utility>
class A
{
private:
double d;
std::string s;
public:
A (double d0, std::string s0) : d { d0 }, s { s0 } { }
};
class B
{
private:
long l;
public:
B (long l0) : l { l0 } { }
};
template <typename Tx, typename Ty, typename Tz>
class bar
{
private:
template <typename ... Ts>
using tpl = std::tuple<Ts...>;
template <std::size_t ... Is>
using is = std::index_sequence<Is...> const;
template <std::size_t N>
using mis = std::make_index_sequence<N>;
Tx x;
Ty y;
Tz z;
template <typename ... Tsx, std::size_t ... Isx,
typename ... Tsy, std::size_t ... Isy,
typename ... Tsz, std::size_t ... Isz>
bar (tpl<Tsx...> const & tx0, is<Isx...> const &,
tpl<Tsy...> const & ty0, is<Isy...> const &,
tpl<Tsz...> const & tz0, is<Isz...> const &)
: x { std::get<Isx>(tx0) ... },
y { std::get<Isy>(ty0) ... },
z { std::get<Isz>(tz0) ... }
{ }
public:
template <typename ... Tsx, typename ... Tsy, typename ... Tsz>
bar (tpl<Tsx...> const & tx0,
tpl<Tsy...> const & ty0,
tpl<Tsz...> const & tz0)
: bar(tx0, mis<sizeof...(Tsx)> {},
ty0, mis<sizeof...(Tsy)> {},
tz0, mis<sizeof...(Tsz)> {})
{ }
};
int main()
{
bar<A, B, A> aba{ std::make_tuple(2.3, "str1"),
std::make_tuple(4),
std::make_tuple(5.4, "str2") };
bar<B, A, B> bab{ std::make_tuple(3),
std::make_tuple(3.2, "str3"),
std::make_tuple(5) };
}
Unfortunately this example use std::make_index_sequence and std::index_sequence that are C++14 features.
If you want implement foo in C++11, you can implement the following structs struct indexSeq and struct indexSeqHelper, to substitute std::index_sequence and std::make_index_sequence
template <std::size_t ...>
struct indexSeq
{ };
template <std::size_t N, std::size_t ... Next>
struct indexSeqHelper
{ using type = typename indexSeqHelper<N-1U, N-1U, Next ... >::type; };
template <std::size_t ... Next >
struct indexSeqHelper<0U, Next ... >
{ using type = indexSeq<Next ... >; };
and define is and mis as follows
template <std::size_t ... Is>
using is = indexSeq<Is...>;
template <std::size_t N>
using mis = typename indexSeqHelper<N>::type;
The static type of all variables must be known at compile time, so it cannot change based on the value of a run time object. The way to make this work is to make x, y, and z all have the type std::uniqe_ptr<foo> and then dynamically allocate an A or B object at run time:
class bar {
public:
bar(some_type something) {
if (something == some_value) {
b.x = new A(3.14, 12.34);
} else {
b.x = new B(456.78);
}
}
private:
int x_type;
std::unique_ptr<foo> x;
//...
};
int main() {
bar b(whatever());
}
In this case you should also declare foo::~foo() to be virtual so that you ensure the derived objects get destroyed correctly.
It would also be a generally Good Idea™ to eliminate x_type and friends entirely and write code that doesn't care about the actual type of x once it's created.
I was wondering if it is possible to make bar a template class with multiple template parameters, but I am not sure if that is possible either as the parameter type depends on another parameter?
I don't know if this helps, but I'll let it here just in case.
You see, different specializations of a template can inherit from different classes. So that you can have:
// fwd decl
template <int kind> class bar;
template <> class bar<1> : public A {
public:
bar(double x, double y) : A(x,y) { }
};
template <> class bar<2> : public B {
public:
bar(double a) : B(a) { }
};
At later stage, when you come with a class C : public foo, you just assign another kind to a new bar template specializations and there you have it: using bar as a unifying name (warning... but not a unifying type - not other than the common foo ancestor. bar<1> and bar<2> will be two different types)
So, Ok, if you don't want inheritance, you can have it by different has-a in specific bar template specializations.
Like
template <int kind> class bar;
template <> class bar<1> {
A val;
public:
bar(double x, double y) : val(x,y) { }
void doSomething2(...) {
// use the val of type A
}
};
template <> class bar<2> {
B val;
double y_;
public:
bar(double x, double y) : val(x), y_(y) { }
void doSomething2(...) {
// use the val of type B and a separate y_
}
};
I though about using template data member and defining the type in
constructor, where I get the values for the types but apparently that
is not possible at least in C++11
C++11 comes with the standard schema of dealing with templated construction depending on some parameter by using make_* template function creating appropriate type of object. See e.g. make_tuple function:
auto t = std::make_tuple(1, "abc", 1.0);
// decltype(t) == std::tuple<int, char const*, double>
This can be implemented by creating template class and template construction function:
template <class T>
struct foo {
T t;
foo(T t): t(t) { }
};
template <class T>
foo<T> make_foo(T t) { return foo<T>(t); }
For example:
template<class... keys>
struct{
{ virtual keys* getContents(foo* Foo) const = 0 }...;
}
or:
template<class... keys>
struct{
virtual bar* getBar( keys* Foo )... const = 0;
}
Or anything with similar effect?
A function or a method cannot return a parameter pack.
A function can return a std::tuple, though:
template<class... keys>
struct something {
virtual std::tuple<keys...> getContents(foo* Foo) const = 0;
}
You could also specialize this template for a single type, and return the type instead of a one-element tuple; and specialize it for an empty parameter pack, and return a void.
EDIT:
You clarified your question. You were trying to do something different, and your initial explanation was understandably somewhat off the mark.
You can accomplish what you're looking, but it's a little bit more complicated, and requires recursive templates and specialization, but looks like this is what you want.
class bar;
template<typename ...Keys> struct getcontents_base;
template<>
struct getcontents_base<> {
};
template<typename firstKey, typename ...remainingKeys>
struct getcontents_base<firstKey, remainingKeys...>
: getcontents_base<remainingKeys...> {
virtual bar *getBar(firstKey *foo) const=0;
};
struct getcontents : public getcontents_base<int, char> {
bar *getBar(int *) const override {}
bar *getBar(char *) const override {}
};
struct notgetcontents : public getcontents_base<int, char> {};
void foo()
{
struct getcontents c; // This will compile fine.
struct notgetcontents c2; // This will result in a compilation error
// because the virtual methods have not
// been defined.
}
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.
This makes no sense to me. GCC is complaining that the call below in main() to processMsg() is ambiguous, even though all of the template-created processMsg() calls are reported back as candidates. I've tried implementing this variadic template prototype three different ways and they all lead back to this same issue of ambiguous request. I did get closer when I broke the template implementation up into different cases for and but then I could the compiler could only resolve the first lookup in the tuple.
I've pasted a small example. I'm sure I'm missing something simple....
#include <tuple>
//----------------------------------------------------------------------
//
class MessageBase
{
public:
MessageBase( const int _id ) : m_id( _id ) {}
virtual int getMessageID() const { return( m_id ); }
private:
const int m_id;
};
#define MESSAGE( NAME, VAL ) \
class Message##NAME : public MessageBase { \
public: \
Message##NAME() : MessageBase( VAL ) { } \
};
MESSAGE( One, 1 );
MESSAGE( Two, 2 );
MESSAGE( Ten, 10 );
//----------------------------------------------------------------------
//
template< typename T >
struct MyMessageInterface {
virtual void processMsg( const T& t ) { }
};
template< typename... T >
struct MyMessageHandler : public MyMessageInterface< T >...
{};
template< typename... T >
struct MyMessageHandler< std::tuple< T... > >
: public MyMessageInterface< T >...
{};
//----------------------------------------------------------------------
//
typedef std::tuple< MessageOne, MessageTwo, MessageTen > Foople;
int main()
{
MyMessageHandler< Foople > mmh;
mmh.processMsg( MessageOne() );
}
You could add a forwarder to the specialization of MyMessageHandler:
template< typename... T >
struct MyMessageHandler< std::tuple< T... > >
: public MyMessageInterface< T >...
{
template< typename U >
void processMsg( const U& u )
{
MyMessageInterface< U >::processMsg( u );
}
};
Live example
The reason you need to do something like this (or what Jarod42 proposed) is that the virtual methods of the base classes are not visible from the derived class when the name is ambiguous. Normally you'd add a using declaration to pull in what you need, but in your case a forwarder might be easier.
You may rewrite MyMessageHandler as follow: Live example
template <typename... Ts> struct MyMessageHandler;
template <typename T> struct MyMessageHandler<T>
{
virtual void processMsg(const T&) { }
};
template <typename T, typename...Ts>
struct MyMessageHandler<T, Ts...> : MyMessageHandler<T>, MyMessageHandler<Ts...>
{
using MyMessageHandler<T>::processMsg;
using MyMessageHandler<Ts...>::processMsg;
};
template <typename... Ts>
struct MyMessageHandler<std::tuple<Ts...>> : public MyMessageHandler<Ts...>
{
};
You have to (unfortunately) explicitly disambiguate the base class that you want to call:
int main()
{
MyMessageHandler< Foople > mmh;
mmh.MyMessageInterface<MessageOne>::processMsg( MessageOne() );
return 0;
}
You can bury the cast in another template if you like:
template <typename Handler, typename Message>
void caller(Handler &h, const Message &m)
{
h.MyMessageInterface<Message>::processMsg( m );
}
int main()
{
MyMessageHandler< Foople > mmh;
caller(mmh, MessageOne());
return 0;
}
The problem is that member look-up is ambiguous because all of the MyMessageInterface<T>s are a direct base class of MyMessageHandler.
We need to pull in the set of names into MyMessageHandler itself so that we can form the overload set with those names.
First approach might be to do something like: using TMessageInterface<T>::processMsg;... but of course that's not legal.
My suggestion would be to either do what #Jarod42 did to recursively pull in the processMsg functions, or you can do:
template <typename... Ts>
struct MyMessageHandler : MyMessageInterface<Ts>... {
template <typename Msg>
void processMsg(const Msg &msg) {
MyMessageInterface<Msg>::processMsg(msg);
}
};
which invokes the specific base class' processMsg.
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;
};