Imagine I had some objects that were all related to some interface class base. However, all of these objects are templated by some integer DIM (dimension). I have assumed all derivatives of base have a static member int number() and a static string InputName. The idea is to register this static method number(). (Really each class will have whole static interface.)
Registration.hpp
template <int DIM>
class objectRegistry
{
public:
template<typename T>
Register()
{
//something like interface_map[T::InputName] = T::number;
}
private:
static inline std::map<std::string, std::function<int ()>> interface_map;
}
Header1.hpp
template <int DIM>
class base
{
public:
static inline const std::string InputName = "base";
static int number() { return 1; };
base(){};
};
//todo: Some Registration Here
Header2.hpp
template <int DIM>
class derived : public base<DIM>, public AutomaticRegister<DIM, derived<DIM>>
{
public:
static inline std::string InputName = "derived";
static int number() { return 4; };
derived(){};
};
//todo: Some Registration Here
hearder3.hpp
template <int DIM, typename extra_type>
class derived2 : public base<DIM>, public AutomaticRegister<DIM, derived2<DIM,extra_type>>
{
public:
static inline std::string InputName = "derived2 " + std::string(typeid(extra_type).name());
static int number() { return 5; };
extra_type member;
};
//todo: Some Registration Here
Can I create an automatic registration system for derived objects (all derived from base); ideally, one that exists in the same header file as the object definition. I would like, for example, objectRegistry<3> to know that derived<3>, derived2<3,int>, and derived<3,double> exist. I have tried these methods:
Best way to for C++ types to self register in a list?
https://www.bfilipek.com/2018/02/factory-selfregister.html
However, because everything is buried in the template< int DIM>, it is never instantiated.
Is there a way I can force derived to instantiated when objectRegistry is instantiated with a particular template value?
Either of the two approaches you linked to will work.
Your problem is that you are using class templates, not classes.
If you did this
class Something : public AutomaticRegister<Something>
{
// ...
};
then you would get automatic registry, because Something is a class.
You have class templates, which are not anything like a type at all.
The registration happens by instantiating the registration class, which is a base class of your class template.
So, in order to instantiate the registration class, you need the stuff you want registered to be treated as a type. Thus, you need to instantiate some part of the class, either by creating an instance of one of the templates...
derived2<1, double> d2_1_double;
or by explicitly instantiating the entire class template...
template class derived2<1, double>;
or by explicitly instantiating some member of the class template, like the number function...
template int derived2<1, double>::number();
or by creating an actual derived class...
struct d2_1_double : derived2<1, double> { };
or some other way to stamp out a class from a class template.
However, a very minor change to the registration class template (adding a type member alias) gives us a mechanism to register them explicitly in bulk, and does not require inheriting from the registration mechanism.
To demonstrate, I added a bit of extremely simple non-production-quality code. To do so, I added a non-standard function to get a unique name for a type that will work for gcc and clang, but no idea about other compilers. It is not necessary, just makes it easier for me.
#include <functional>
#include <iostream>
#include <string_view>
#include <unordered_map>
template <typename ... Ts> struct TypeList { };
template <typename T>
constexpr auto
fname()
{
return __PRETTY_FUNCTION__;
}
class Registry
{
std::unordered_map<std::string_view, std::function<int()>> map;
public:
void insert(std::string_view key, std::function<int()> value) {
assert(map.find(key) == map.end());
std::cout << "Register \"" << key << "\", " << value() << '\n';
map[key] = std::move(value);
}
int operator()(std::string_view key) const {
return map.at(key)();
}
};
template <int DIM>
Registry & registry()
{
static Registry result;
return result;
}
And here is the stuff to do the auto-registration, a modified version of the answer from one of your links.
template <typename T>
class AutoRegister
{
struct helper {
helper() { registry<T::dim>().insert(fname<T>(), T::number); }
};
/* inline */ static helper h;
template<helper&> struct ref { using type = AutoRegister; };
public:
using type = typename ref<h>::type;
};
// NOTE: A bug in gcc forces this usage rather than just using inline.
template <typename T>
typename AutoRegister<T>::helper AutoRegister<T>::h;
Then, with some class templates similar to yours...
template <int DIM>
struct Bar
{
static constexpr int dim = DIM;
static int number() { return dim*100 + 99; }
};
template <int DIM, typename T>
struct Baz
{
static constexpr int dim = DIM;
static int number() { return dim*100 + 86; }
};
template <int DIM, typename ... Ts>
struct Foo
{
static constexpr int dim = DIM;
static int number() { return dim*100 + 42; }
};
and a helper alias template...
template <typename ... Ts>
using RegisterTypes = TypeList<typename AutoRegister<Ts>::type...>;
We can register the stuff we want. The second one has some duplicates just to show that stuff gets registered once.
using Registered = RegisterTypes<Bar<0>, Bar<1>, Baz<1>, Foo<1>>;
using Registered2 = RegisterTypes<Bar<2>, Bar<1>, Baz<1>, Foo<1>>;
int main()
{
}
Running the program results in the following output...
Register "auto fname() [T = Bar<0>]", 99
Register "auto fname() [T = Bar<1>]", 199
Register "auto fname() [T = Baz<1, int>]", 186
Register "auto fname() [T = Foo<1, int>]", 142
Register "auto fname() [T = Bar<2>]", 299
Register "auto fname() [T = Foo<1, int, double>]", 142```
Related
I'd like to have a static polymorphism with the parent class having a template std::array size. This code works fine:
#include <iostream>
#include <array>
using namespace std;
template <size_t size>
class Message
{
public:
size_t GetSize() { return size; }
private:
std::array<uint8_t, size> data_{};
};
class Command : public Message<12>
{
public:
static const size_t kCmdSize{12};
private:
};
class Reply : public Message<16>
{
public:
static const size_t kCmdSize{12};
private:
};
int main()
{
Command cmd{};
Reply rpl{};
cout << "Size: " << cmd.GetSize() << "|" << rpl.GetSize() << endl;
return 0;
}
But I'm not a huge fan of magic numbers.
Is there any way to use a constant declared in the child class as the parameter to the parent class? Something like that:
class Command : public Message<kCmdSize>
{
public:
static const size_t kCmdSize{12};
private:
};
Using this directly attempts to use a variable from a class that doesn't exist yet.
Using C++14.
If you're fine with one extra layer of indirection, then you can use a "traits class" kind of solution:
#include <array>
#include <cstdint>
template <class T> struct MessageSize;
template <std::size_t size>
class Message {
public:
std::size_t GetSize() { return size; }
private:
std::array<std::uint8_t, size> data_{};
};
// Forward declare class for upcoming specialization.
class Command;
// Specialize message size for Command class.
template <> struct MessageSize<Command> {
static constexpr std::size_t size = 12;
};
class Command : public Message<MessageSize<Command>::size> { };
Note that in my example the Message class itself does not use the MessageSize one. You could do that as well, and have Command inherit from Message<Command> instead, but that would make your inheritance tree look a whole lot different (i.e. classes with the same message length wouldn't have the same base class anymore).
You could of course add another layer of indirection in there, where you inherit from e.g. MessageBase<Command> which in turn inherits from Message<MessageSize<Command>::size>.
That's common problem and there is solution used widely, e.g. in implementations of stream components of C++ library. The type definitions and constants related to concrete derived class became part of specialization for a trait class:
template <class T>
struct CommandTrait;
template <class T>
struct Message : public CommandTrait<T>
{
constexpr size_t GetSize() { return this->kCmdSize; } // or Message::kCmdSize, the same in this case
std::array<std::uint8_t, Message::size> data_{};
};
template <size_t _Sz, size_t _CSc = 12 >
struct MessageSize {
static constexpr std::size_t size = _Sz;
static constexpr size_t kCmdSize{ _CSc };
};
template <>
struct CommandTrait<struct Command> : MessageSize<12> {};
template <>
struct CommandTrait<class Reply> : MessageSize<16> {};
class Command : public Message<Command>
{
};
class Reply : public Message<Reply>
{
};
Note that this-> is important to suggest compiler that "kCmdSize" is a name depending on template's parameter. You need a template-dependant name (i.e. qualified for static use or using this-> for runtime). That tells compiler to expect that such name exist or will be existing in future, at time of instantiation. SHould not forget about possibility of using constexpr:
template <class T>
struct Message : public CommandTrait<T>
{
static constexpr size_t GetSize() { return Message::kCmdSize; }
std::array<std::uint8_t, GetSize()> data_{};
};
Trait class may have a common base, but generally type erasure is not required where such structs are used.
How about something like this?
Is there a concern to pass the number from your main-instance instead of letting it hang open in the class impl.
#include <iostream>
#include <array>
using namespace std;
template <size_t size>
class Message
{
public:
size_t GetSize() { return size; }
private:
std::array<uint8_t, size> data_{};
};
template<size_t N>
class Command : public Message<N>
{
public:
static const size_t kCmdSize{N};
private:
};
int main()
{
Command<12> cmd{};
cout << "Size: " << cmd.GetSize() << endl;
return 0;
}
Is it possible to create a class template with a member function definition only if the object created is of a specific type?
I've created a template class I will use for storing either int or doubles, but for doubles I would like to be able to set precision too (objects created with myclass < double> should have this functionality, but for myclass< int> there is no need for that to be present at all).
I know I can use a base class template, and create new classes "myInt", "myDouble" using that and implement the functionality only in the myDouble class, but I think it would be cleaner to define the functionality (both the function and a member variable) for doubles in the class template, if that's possible and preferable?
Let's add an example to show what I want to do:
#include <iostream>
#include <iomanip>
class commonBase{
public:
void setState(int state);
virtual void print() = 0;
private:
int _my_state;
};
template <typename T>
class generalObject : public commonBase {
public:
void value(T value);
void print(){ std::cout << "My value: " << _my_value << std::endl; }
private:
T _my_value;
};
template <typename T>
void generalObject<T>::value(T value){
_my_value = value;
}
// Is there any way do specialize only only whats different from the generalObject template?
// Here I thought I could specialize the case where a generalObject is created of <double>, but
// when I do, nothing is derived from generalObject (or at least not visible as far as I can tell)
template<>
class generalObject<double>{
public:
void setPrecision(int precision){ _my_precision = precision; }
// here I would like a special implementation of print(), which overrides the print() in generalObject
// and instead also prints according to the precision set when the object is of <double> type.
// Row below an example which doesn't work (compiler error, _my_value undefined)
void print(){ std::cout << "My value: " << std::setprecision(_my_precision) << _my_value << std::endl; }
private:
int _my_precision;
};
int main(int argc, char* argv[]){
generalObject<int> o1;
o1.value(1);
o1.print();
o1.setState(1); //inherited from the commonBase
generalObject<double> o2;
o2.setPrecision(2);
o2.value(2); //here value isn't available (compile error)
o2.print();
o2.setState(123); //also isn't available (compile error)
}
Sure.
template <typename T> class Poly;
void set_precision(Poly<double>* self, int a) {};
If you really want dot notation you can then add:
template <typename T> class Poly {
public: void set_precision(int a){::set_precision(this,a);}
...
However I think you should think about what you're trying to accomplish. If MyInt and MyDouble have different fields and different methods and different implementations, they should probably be different classes.
This can be solved using template specialization.
We first define a common template...
template< typename T >
struct myclass
{
// common stuff
};
... and specialize that for double:
template<>
struct myclass<double>
{
int precision = 10;
void setprecision( int p ){ precision = p; }
};
Now the setprecision() method can only be called for myclass<double>. The compiler will complain if we try to call it for anything else, like myclass<int>.
int main()
{
myclass<double> d;
d.setprecision( 42 ); // compiles
myclass<int> i;
i.setprecision( 42 ); // fails to compile, as expected
}
Demo.
The basic way to have a member function of a class template exist only for some template parameters is to create a specialization of the class template for those template parameters.
template<typename T>class X{
// general definition
};
template<>class X<double>{
// double-specific definition
};
The downside of this is that the specialization will need to duplicate anything that is common. One way to address this is to move the common things out to a base class template:
template<typename T>class Xcommon{
// common stuff
};
template<typename T>class X: public Xcommon<T>{
// general definition
};
template<>class X<double>: public Xcommon<double>{
// double-specific definition
};
Alternatively, you can do it the other way: put the common stuff in the derived class, and the extras in the base, and specialize the base:
template<typename T>class Xextras{
// empty by default
};
template<typename T>class X: public Xextras<T>{
// common definition
};
template<>class Xextras<double>{
// double-specific definition
};
Either way can work; which is better depends on the details.
Both these methods work for data members and member functions.
Alternatively, you can use enable_if to mean that member functions are not selected by overload resolution if the template parameter doesn't meet a required condition. This requires that the member function is itself a template.
template<typename T>class X{
template<typename U=T> // make it a template,
std::enable_if<std::is_same_v<U,double>> double_specific_function(){
// do stuff
}
};
I wouldn't recommend this option unless there is no other choice.
If the question is about a member function, then here is one of the ways to do it without class template specialization:
#include <iostream>
#include <type_traits>
template <typename T>
struct Type {
template <typename U = T,
typename = typename std::enable_if<std::is_same<U, double>::value>::type>
void only_for_double() {
std::cout << "a doubling" << std::endl;
}
};
int main() {
Type<int> n;
Type<double> d;
// n.only_for_double(); // does not compile.
d.only_for_double();
}
Example on ideone.com
If you require a data-member presence based on the template parameter, you will have to do some kind of specialization, in which case it is, probably, simpler to put the function into corresponding specialization.
EDIT: After OP made his question more specific
Here is one way to do it without extra class and getting rid of virtual functions. Hope it helps.
#include <iostream>
#include <iomanip>
template <typename T, typename Derived = void>
class commonBase {
public:
void setState(int state) {
_my_state = state;
}
void value(T value) {
_my_value = value;
}
template <typename U = Derived,
typename std::enable_if<std::is_same<U, void>::value,
void * >::type = nullptr>
void print() const {
std::cout << "My value: " << _my_value << std::endl;
}
template <typename U = Derived,
typename std::enable_if<!std::is_same<U, void>::value,
void * >::type = nullptr>
void print() const {
static_cast<Derived const *>(this)->_print();
}
protected:
T _my_value;
int _my_state;
};
template <typename T>
class generalObject : public commonBase<T> {
};
template<>
class generalObject<double> : public commonBase<double, generalObject<double>> {
private:
friend commonBase<double, generalObject<double>>;
void _print() const {
std::cout << "My value: " << std::setprecision(_my_precision) <<
_my_value << std::endl;
}
public:
void setPrecision(int precision){ _my_precision = precision; }
private:
int _my_precision;
};
int main(){
generalObject<int> o1;
o1.value(1);
o1.print();
o1.setState(1);
generalObject<double> o2;
o2.setPrecision(2);
o2.value(1.234);
o2.print();
o2.setState(123);
}
Same code on ideone.com
To implement a property system for polymorphic objects, I first declared the following structure:
enum class access_rights_t
{
NONE = 0,
READ = 1 << 0,
WRITE = 1 << 1,
READ_WRITE = READ | WRITE
};
struct property_format
{
type_index type;
string name;
access_rights_t access_rights;
};
So a property is defined with a type, a name and access rights (read-only, write-only or read-write). Then I started the property class as follows:
template<typename Base>
class property : property_format
{
public:
template<typename Derived, typename T>
using get_t = function<T(const Derived&)>;
template<typename Derived, typename T>
using set_t = function<void(Derived&, const T&)>;
private:
get_t<Base, any> get_f;
set_t<Base, any> set_f;
The property is associated to a base type, but may (and will) be filled with accessors associated to an instance of a derived type. The accessors will be encapsulated with functions accessing std::any objects on an instance of type Base. The get and set methods are declared as follows (type checking are not shown here to make the code minimal):
public:
template<typename T>
T get(const Base& b) const
{
return any_cast<T>(this->get_f(b));
}
template<typename T>
void set(Base& b, const T& value_)
{
this->set_f(b, any(value_));
}
Then the constructors (access rights are set to NONE to make the code minimal):
template<typename Derived, typename T>
property(
const string& name_,
get_t<Derived, T> get_,
set_t<Derived, T> set_ = nullptr
):
property_format{
typeid(T),
name_,
access_rights_t::NONE
},
get_f{caller<Derived, T>{get_}},
set_f{caller<Derived, T>{set_}}
{
}
template<typename Derived, typename T>
property(
const string& name_,
set_t<Derived, T> set_
):
property{
name_,
nullptr,
set_
}
{
}
The functions passed as arguments are encapsulated through the helper structure caller:
private:
template<typename Derived, typename T>
struct caller
{
get_t<Derived, T> get_f;
set_t<Derived, T> set_f;
caller(get_t<Derived, T> get_):
get_f{get_}
{
}
caller(set_t<Derived, T> set_):
set_f{set_}
{
}
any operator()(const Base& object_)
{
return any{
this->get_f(
static_cast<const Derived&>(object_)
)
};
}
void operator()(Base& object_, const any& value_)
{
this->set_f(
static_cast<Derived&>(object_),
any_cast<Value>(value_)
);
}
};
Now, considering these dummy classes.
struct foo
{
};
struct bar : foo
{
int i, j;
bar(int i_, int j_):
i{i_},
j{j_}
{
}
int get_i() const {return i;}
void set_i(const int& i_) { this->i = i_; }
};
I can write the following code:
int main()
{
// declare accessors through bar methods
property<foo>::get_t<bar, int> get_i = &bar::get_i;
property<foo>::set_t<bar, int> set_i = &bar::set_i;
// declare a read-write property
property<foo> p_i{"bar_i", get_i, set_i};
// declare a getter through a lambda
property<foo>::get_t<bar, int> get_j = [](const bar& b_){ return b_.j; };
// declare a read-only property
property<foo> p_j{"bar_j", get_j};
// dummy usage
bar b{42, 24};
foo& f = b;
cout << p_i.get<int>(f) << " " << p_j.get<int>(f) << endl;
p_i.set<int>(f, 43);
cout << p_i.get<int>(f) << endl;
}
My problem is that template type deduction doesn't allow me to declare a property directly passing the accessors as arguments, as in:
property<foo> p_i{"bar_i", &bar::get_i, &bar::set_i};
Which produces the following error:
prog.cc:62:5: note: template argument deduction/substitution failed:
prog.cc:149:50: note: mismatched types std::function<void(Type&, const Value&)> and int (bar::*)() const
property<foo> p_i{"bar_i", &bar::get_i, set_i};
Is there a way to address this problem while keeping the code "simple"?
A complete live example is available here.
std::function is a type erasure type. Type erasure types are not suitable for deduction.
template<typename Derived, typename T>
using get_t = function<T(const Derived&)>;
get_t is an alias to a type erasure type. Ditto.
Create traits classes:
template<class T>
struct gettor_traits : std::false_type {};
this will tell you if T is a valid gettor, and if so what its input and output types are. Similarly for settor_traits.
So
template<class T, class Derived>
struct gettor_traits< std::function<T(Derived const&)> >:
std::true_type
{
using return_type = T;
using argument_type = Derived;
};
template<class T, class Derived>
struct gettor_traits< T(Derived::*)() >:
std::true_type
{
using return_type = T;
using argument_type = Derived;
};
etc.
Now we got back to the property ctor:
template<class Gettor,
std::enable_if_t< gettor_traits<Gettor>{}, int> =0,
class T = typename gettor_traits<Gettor>::return_value,
class Derived = typename gettor_traits<Gettor>::argument_type
>
property(
const string& name_,
Gettor get_
):
property_format{
typeid(T),
name_,
access_rights_t::NONE
},
get_f{caller<Derived, T>{get_}},
nullptr
{
}
where we use SFINAE to ensure that our Gettor passes muster, and the traits class to extract the types we care about.
There is going to be lots of work here. But it is write-once work.
My preferred syntax in these cases would be:
std::cout << (f->*p_i)();
and
(f->*p_i)(7);
where the property acts like a member function pointer, or even
(f->*p_i) = 7;
std::cout << (f->*p_i);
where the property transparently acts like a member variable pointer.
In both cases, through overload of ->*, and in the second case via returning a pseudo-reference from ->*.
At the end of this answer is a slightly different approach. I will begin with the general problem though.
The problem is &bar::get_i is a function pointer to a member function while your alias is creating a function object which needs the class as additional template parameter.
Some examples:
Non member function:
#include <functional>
void a(int i) {};
void f(std::function<void(int)> func)
{
}
int main()
{
f(&a);
return 0;
}
This works fine. Now if I change a into a struct:
#include <functional>
struct A
{
void a(int i) {};
};
void f(std::function<void(int)> func)
{
}
int main()
{
f(std::function<void(int)>(&A::a));
return 0;
}
this gets the error:
error: no matching function for call to std::function<void(int)>::function(void (A::*)(int))'
because the std::function object also need the base class (as you do with your alias declaration)
You need a std::function<void(A,int)>
You cannot make your example much better though.
A way to make it a "bit" more easier than your example would maybe be this approach using CRTP.
#include <functional>
template <typename Class>
struct funcPtr
{
template <typename type>
using fun = std::function<void(Class,type)>;
};
struct A : public funcPtr<A>
{
void a(int i) {};
};
void f(A::fun<int> func)
{
};
int main()
{
f(A::fun<int>(&A::a));
return 0;
}
And each your "derived" classes derives from a funcPtr class which "auto generates" the specific alias declaration.
I'm currently playing around with templates in C++ and got stuck with template template parameters.
Lets say I have the following classes:
template<typename T>
struct MyInterface
{
virtual T Foo() = 0;
}
class MyImpl : public MyInterface<int>
{
public:
int Foo() { /*...*/ }
};
template< template<typename T> typename ImplType>
class MyHub
{
public:
static T Foo()
{
ImplType i;
return i.Foo();
}
private:
MyHub() { }
~MyHub() { }
};
In essence I would like to have a static class like MyHub that accepts an implementation of MyInterface and provides certain static methods to use them like static T Foo().
Then I tried to use MyHub:
int main()
{
int i = MyHub<MyImpl>::Foo();
return 0;
}
Unfortunately I always end up getting an error saying that the type T (of static T Foo() in MyHub) does not name a type.
I would expect that it works because
the template parameter of the template parameter Impl is named T
MyHub is a templated class with one template parameter and contains a method Foo
So far I couldn't find a solution for this after digging through documentations and google results so I hope some of you can help me.
You can use typedefs. Also, since your implementation classes are not template class, there is no need for template template parameters.
#include <iostream>
#include <string>
template<typename T>
struct MyInterface
{
virtual T Foo() = 0;
typedef T Type;
};
class MyIntImpl : public MyInterface<int>
{
public:
int Foo() { return 2; }
};
class MyStringImpl : public MyInterface<std::string>
{
public:
std::string Foo() { return "haha"; }
};
template<class ImplType>
class MyHub
{
public:
static typename ImplType::Type Foo()
{
ImplType i;
return i.Foo();
}
private:
MyHub() { }
~MyHub() { }
};
int main()
{
std::cout << MyHub<MyIntImpl>::Foo() << "\n"; // prints 2
std::cout << MyHub<MyStringImpl>::Foo() << "\n"; // print haha
return 0;
}
Here is an example.
MyImpl is not a class template; so can't be passed as the template parameter of MyInterface.
You could change your MyInterface, MyImpl and MyHub classes to:
template<typename T>
class MyInterface{
public:
virtual T foo() = 0;
};
class MyImpl: public MyInterface<int>{
public:
using value_type = int;
value_type foo(){ return 1; /* dummy */ }
};
template<typename Impl, typename = std::enable_if_t<std::is_base_of<Impl, MyInterface<typename Impl::value_type>>::value>>
class MyHub{
public:
static auto foo(){
static Impl i;
return i.foo();
}
};
Which lets you use it the same way you are in your example.
The std::is_base_of check might be a little unnecessary in this case; but, this way you can't accidentally pass in another class that isn't derived from MyInterface with a method foo().
The STL uses value_type as a place holder for the underlying type of a template class. You could possibly do the same for your solution.
template<typename T>
struct MyInterface
{
typedef T value_type;
virtual T Foo() = 0;
}
class MyImpl : public MyInterface<int>
{
public:
int Foo() { /*...*/ }
};
template<typename ImplType>
class MyHub
{
public:
static typename ImplType::value_type Foo()
{
ImplType i;
return i.Foo();
}
private:
MyHub() { }
~MyHub() { }
};
Also note that in c++14, typename ImplType::value_type can be replaced by auto:
static auto Foo()
{
ImplType i;
return i.Foo();
}
The names of template parameters of template template parameters are effectively a purely documentational construct—they don't get included in the containing template's scope.
There's good reason for that: there is nothing to whcih they could refer in the containing template. When you have a template template parameter, you must pass a template as the argument to it, and not an instantiation of a template. In other words, you're passing a template without arguments as the argument.
This means your code is simply wrong—you're using MyImpl as an argument for MyHub, but MyImpl is a class. MyHub expects a template, not a class. The correct instantiation of MyHub would be MyHub<MyInterface>. Not that there are no template arguments after this use of MyInterface; we are passing in the template itself, not an instantiation of it.
Template template parameters are used rather rarely in practice. You only use them if you want to instantiate the parameter template with your own types. So I would expect your MyHub code to do something like this:
template <template <class> class ImplTemplate>
struct MyHub
{
typedef ImplTemplate<SomeMyHub_SpecificType> TheType;
// ... use TheType
};
This doesn't seem to be what you want to do. I believe you want a normal type template parameter, and provide a nested typedef for its T. Like this:
template <class T>
struct MyInterface
{
typedef T ParamType; // Added
virtual T Foo() = 0;
};
template<class ImplType>
class MyHub
{
typedef typename ImplType::ParamType T;
public:
static T Foo()
{
ImplType i;
return i.Foo();
}
private:
MyHub() { }
~MyHub() { }
};
int main()
{
int i = MyHub<MyImpl>::Foo();
return 0;
}
Now I have a template class
template <class T>
class b
{
void someFunc() {
T t;
t.setB();
}
};
I know the template T only will be instantiated into 2 classes.
class D
{
public:
void setB();
};
class R
{
public:
void SetB();
};
As we can see, class D's function name setB is not the same as R's function SetB. So in template class b I cannot only just use setB. So is there some method if I cannot revise D or R? Can I add some wrapper or trick into the template class to solve this problem?
Maybe a trait class can help you:
struct Lower {};
struct Upper {};
// trait for most cases
template <typename T>
struct the_trait {
typedef Lower Type;
};
// trait for special cases
template <>
struct the_trait<R> {
typedef Upper Type;
};
template <class T>
class b {
public:
void foo() {
foo_dispatch(typename the_trait<T>::Type());
}
private:
void foo_dispatch(Lower) {
T t;
t.setB();
}
void foo_dispatch(Upper) {
T t;
t.SetB();
}
};
As #Arunmu pointed, this technique is also known as Tag Dispatching.
You can specialise your template for the class that has different semantics:
template<>
class b<R>
{
void doWork() {
R obj;
obj.SetB();
// or R::SetB() if it was a static method.
}
};
Instead of using self programmed traits you can also check for the existence of a function with SFINAE.
If you want to switch your called method only one of them must exist in each class. My method provided will not work if the check find more then one of the tested methods!
The following example is written for C++14 but can also be used with c++03 if you replace the new library functions with self implemented ones ( which is of course not convenient )
The testing class has_Foo and has_Bar can also be embedded in a preprocessor macro, but I wrote it expanded to makes the things easier to read.
How it works and why there are some more intermediate steps are necessary are explained in the comments. See below!
#include <iostream>
// First we write two classes as example. Both classes represents
// external code which you could NOT modify, so you need an
// adapter to use it from your code.
class A
{
public:
void Foo() { std::cout << "A::Foo" << std::endl; }
};
class B
{
public:
void Bar() { std::cout << "B::Bar" << std::endl; }
};
// To benefit from SFINAE we need two helper classes which provide
// a simple test functionality. The solution is quite easy...
// we try to get the return value of the function we search for and
// create a pointer from it and set it to default value nullptr.
// if this works the overloaded method `test` returns the data type
// one. If the first test function will not fit, we cat with ... all
// other parameters which results in getting data type two.
// After that we can setup an enum which evaluates `value` to
// boolean true or false regarding to the comparison function.
template <typename T>
class has_Foo
{
using one = char;
using two = struct { char a; char b;};
template <typename C> static one test( typename std::remove_reference<decltype(std::declval<C>().Foo())>::type* );
template <typename C> static two test( ... ) ;
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
enum { Yes = sizeof(test<T>(0)) == sizeof(one) };
enum { No = !Yes };
};
template <typename T>
class has_Bar
{
using one = char;
using two = struct { char a; char b;};
template <typename C> static one test( typename std::remove_reference<decltype(std::declval<C>().Bar())>::type* );
template <typename C> static two test( ... ) ;
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
enum { Yes = sizeof(test<T>(0)) == sizeof(one) };
enum { No = !Yes };
};
// Now in your adapter class you can use the test functions
// to find out which function exists. If your class
// contains a Foo function the first one compiles and if the
// the class contains a Bar function the second one fits. SFINAE
// disable the rest.
// We need a call helper here because SFINAE only
// fails "soft" if the template parameter can deduced from the
// given parameters to the call itself. So the method
// Call forwards the type to test "T" to the helper method as
// as explicit parameter. Thats it!
template <typename T>
class X: public T
{
public:
template < typename N, std::enable_if_t< has_Foo<N>::value>* = nullptr>
void Call_Helper() { this->Foo(); }
template < typename N, std::enable_if_t< has_Bar<N>::value>* = nullptr>
void Call_Helper() { this->Bar(); }
void Call() { Call_Helper<T>(); }
};
int main()
{
X<A> xa;
X<B> xb;
xa.Call();
xb.Call();
}