In code (just paste and copy)is there a way to avoid repetition/listing of template args(line marked in code):
#include <iostream>
using namespace std;
template<class T,class... V>
struct nullptr_
{
nullptr_(T& obj,V&... args)
{
nullptr_hlp(obj,args...);
}
template<class A>
static void nullptr_hlp(A& a);
{
a = nullptr;
}
template<class A,class... Vs>
static void nullptr_hlp(A& a,Vs&... args)
{
a = nullptr;
nullptr_hlp(args...);
}
};
class X : nullptr_<int*,double*,char*>//IS THERE A WAY TO HAVE JUST nullptr_?
{
int* a;
double* b;
char* c;
typedef nullptr_<decltype(a),decltype(b),decltype(c)> init_;
public:
X():init_(a,b,c)
{
}
};
int main()
{
X x;
return 0;
}
nullptr_<int*,double*,char*> becomes an injected class name within X, so you can refer to it without the argument list:
class X : nullptr_<int*,double*,char*>//can't do away with the list here, unless you want to typedef it
{
int* a;
double* b;
char* c;
//typedef nullptr_<decltype(a),decltype(b),decltype(c)> init_; //don't really need this
public:
X():nullptr_(a,b,c) //can be used without the argument list
{
}
};
How about moving the typedef out of the class in to an anonymous namespace and use that for inheritance?
Related
First of all, the code is restricted to C++11, so I cannot make use of if constexpr
Following is my sample code snippet:
class A{
public:
int a;
int b;
}
class B{
public:
int key;
int val;
}
class C{
public:
int n1;
int n2;
}
class D{
public:
int n1;
int n2;
}
class E{
public:
int n1;
int n2;
}
template<typename T>
void func1(T data) {
if (T == type(A)) { // Just pseudo template-check code
std::cout<<data.a<<data.b; //<------1
} else if (T == type (B)) { // Just pseudo template-check code
std::cout<<data.key<<data.val; //<------2
} else {
std::cout<<data.n1<<data.n2; //<------3
}
int main() {
A a;
B b;
C c;
D d;
E e;
func1(a);
func1(b);
func1(c);
func1(d);
func1(e);
return 0;
}
Currently, I get a compile-time error at,
1: B,D,E,F has no member a & b
&
2: A,D,E,F has no member key & val
&
3. A, B has no member n1 & n2
I tried using is_same() & also this, but I get same compile time error every time.
I cannot make use of C++14/C++17
How could I make use of specialized template functions?
Edited the code to highlight the need of a template.
You can use a function overload and avoid the function template altogether.
void func1(A a)
{
// Type dependent code.
}
void func1(B a)
{
// Type dependent code.
}
A function template makes sense only if there is common code for all the types for which the function call is made. If you have some code that is common to all types and some code that are type dependent, then you can use:
void func1(A a)
{
// Type dependent code.
}
void func1(B a)
{
// Type dependent code.
}
template <typename T>
void func2(T t)
{
// Type independent code.
}
template <typename T>
void func(T obj)
{
func1(obj); // Call function that uses type dependent code.
func2(obj); // Call function that uses type independent code.
}
You must write specializations of the function for the two types your want to use it with.
#include<iostream>
class A{
public:
int a;
int b;
};
class B{
public:
int key;
int val;
};
template<typename T>
void func1(T);
template<>
void func1<A>(A arg) {
std::cout<<"A"<<std::endl;
std::cout<<arg.a<<arg.b;
}
template<>
void func1<B>(B arg) {
std::cout<<"B"<<std::endl;
std::cout<<arg.key<<arg.val;
}
int main(){
A a;
func1(a);
B b;
func1(b);
}
Simple overload does the job.
template <typename T>
void func1(T data)
{
std::cout << data.n1 << data.n2;
}
void func1(A data)
{
std::cout << data.a << data.b;
}
void func1(B data)
{
std::cout << data.key << data.val;
}
https://godbolt.org/z/r7Ee6E
Tweaked a bit: https://godbolt.org/z/xxPWaE
Lets assume we have two classes
struct A
{
int x = 1;
};
struct B
{
int y = 2;
};
I want to have template that will return value of member (in a case of A I want to return value of "x", in case of B I want to return value of "y").
Example call:
const auto myVariable = f<A>();
or
A a;
const auto myVariable = f<A>(a);
I don't want to have 2 template specializations - ideally it would be one template with some kind of "if statement", but maybe it is not possible?
It may be written with C++11 (but not with C++14).
Generally how you are using templates when you have such problems - quite big template and only in one or two places you need to take values from different members - which may be deduced based of type of that variable.
PROBLEM: unnecessary it is not allowed to modify classes A and B
Why use templates at all?
int f(const A& a) { return a.x; }
int f(const B& b) { return b.y; }
Just in case you ask for the template because you want to switch between A and B at compile time...and you have a reason not to simply typedef A or B directly...
struct A
{
int x;
};
struct B
{
int y;
};
struct A1 : public A { int Get() const { return x; } };
struct B1 : public B { int Get() const { return y; } };
// Begin possible shortcut avoiding the template below:
#ifdef USE_A
typedef A1 Bar;
#endif
#ifdef USE_B
typedef B1 Bar;
#endif
// End possible shortcut.
template <class _Base>
struct CompileTimeAOrB
: public _Base
{
int Get() const
{
return _Base::Get();
}
};
#define USE_A
//#define USE_B
#ifdef USE_A
typedef CompileTimeAOrB<A1> Foo;
#endif
#ifdef USE_B
typedef CompileTimeAOrB<B1> Foo;
#endif
EDIT: Since A and B cannot be changed, introduced A1, B1 ;)
#include <iostream>
struct A
{
int value;
A() : value(2) {}
};
struct B
{
int value;
B() : value(4) {}
};
template <typename T>
int GetValue(T t)
{
return t.value;
}
int main()
{
A a;
B b;
std::cout << GetValue(a) << std::endl;
std::cout << GetValue(b) << std::endl;
return 0;
}
In order for it to work, you'd need to have the same variable or function named declared in each class you wanted this to work with.
I have learned this code like inheritance by using template technique on C++. This code works.
#include <iostream>
using namespace std;
template < typename T >
class Base {
public:
explicit Base(const T& policy = T()) : m_policy(policy) {}
void doSomething()
{
m_policy.doA();
m_policy.doB();
}
private:
T m_policy;
};
class Implemented {
public:
void doA() { cout << "A"; };
void doB() { cout << "B"; };
};
int main() {
Base<Implemented> x;
x.doSomething();
return 0;
}
However, is it possible to add arguments with new typename S in doA and doB? For example, this code doesn't work by type/value mismatch errors.
#include <iostream>
using namespace std;
template < typename T, typename S >
class Base {
public:
explicit Base(const T& policy = T()) : m_policy(policy) {}
void doSomething()
{
m_policy.doA(m_s);
m_policy.doB(m_s);
}
private:
T m_policy;
S m_s;
};
template < typename S >
class Implemented {
public:
void doA(S& s) { cout << "A" << s; };
void doB(S& s) { cout << "B" << s; };
};
int main() {
Base<Implemented, int> x;
x.doSomething();
return 0;
}
I guess I must let both class Base and Implemented know about an actual type of S at main(). How can I fix this issue? Thank you for your help in advance.
In this line:
Base<Implemented, int> x;
Implemented is no longer a type, now you made it a template. But Base still expects a type - so give it one:
Base<Implemented<int>, int> x;
When Implemented was a class, you used a template parameter T. Now that Implmented is a template class, you need to use a so called template template parameter, like so:
#include <iostream>
using namespace std;
template < template <class TS> class T, typename S >
class Base {
public:
explicit Base(const T<S>& policy = T<S>()) : m_policy(policy) {}
void doSomething()
{
m_policy.doA(m_s);
m_policy.doB(m_s);
}
private:
T<S> m_policy;
S m_s;
};
template < typename S >
class Implemented {
public:
void doA(S& s) { cout << "A" << s; };
void doB(S& s) { cout << "B" << s; };
};
int main() {
Base<Implemented, int> x;
x.doSomething();
return 0;
}
For example, I have a base class A and its sub-classes B, C and so on. B and C can also has its sub-classes. The structure is a tree with root A. And each class in the tree is assigned a different integer to identify itself. There is no restriction on the integer id's values and orders. Just make sure they are different for different classes.
My question is how to do it smartly (or automatically) by using like template techniques since manual assignment is error-prone. Any way to get the id is fine, like
class A
{
public:
static const id = ...;
};
or
template<class A>
struct Id
{
enum { value = ... };
};
Easiest way is just a function
int nextId() {
static int rval = 1;
return rval++;
}
class A { public: static const id = nextId(); };
class B { public: static const id = nextId(); };
class C { public: static const id = nextId(); };
That will work so long as you do not need to use the IDs in dynamic initialization at the start of the program.
Edit: if that is not sufficient, the next step up is to do the same thing with static variables in a template. This works across compilation units, but is still dynamic initialization time.
template <typename DummyT = void>
struct CommonCounter
{
public:
static int nextId() {
static int rval = 1;
return rval ++;
}
};
template <typename T>
struct IdFor
{
static int value()
{
static int rval = CommonCounter<>::nextId();
return rval;
}
};
class A { public: static const id = IdFor<A>::get(); };
You could do something like this. This should give the same order on the same compiler. You could also modify how you key things to get a known order and detect problems at initialisation time. Simple implementation, not tested.
#include <typeinfo>
class A {
public:
virtual ~A();
static void register_type(std::type_info const& t);
int id() const;
};
template<class T>
struct DoInitA
{
DoInitA() { A::register_type(typeid(T)); }
};
class B : public A
{
static DoInitA<B> s_a_init;
public:
~B() { }
};
//
// Implementation file.
//
#include <vector>
#include <functional>
namespace {
struct TypeinfoLess {
typedef std::reference_wrapper<const std::type_info> value_type;
bool operator()(value_type const& lhs, value_type const& rhs) const {
return lhs.get().before(rhs.get());
}
};
}
typedef std::vector<std::reference_wrapper<const std::type_info>> TypeVector;
static TypeVector s_types;
static bool s_init_complete = false;
A::~A() { }
void A::register_type(std::type_info const& t)
{
static int s_counter = 0;
if (s_init_complete)
throw std::runtime_error("Late initialisation");
s_types.push_back(std::reference_wrapper<const std::type_info>(t));
}
int A::id() const
{
if (!s_init_complete) {
sort(s_types.begin(), s_types.end(), TypeinfoLess());
s_init_complete = true;
}
for (size_t i = 0; i < s_types.size(); ++i)
if (s_types[i].get() == typeid(*this)) return i;
throw std::runtime_error("Uninitialised type");
}
I have a class Foo which uses CRTP to inherit a template method from a parent class and avoid having to provide literally dozens of individual member methods. Something like this:
class Foo : public SomeBarClass<Foo>
{
//..
//from SomeBarClass
public:
template <class T> void onMsg(T* msg);
private:
IFoxMod* foxMod_;
};
Now, in the implementation for onMsg, I would like something like this:
template <class T>
void Foo::onMsg(T* msg)
{
if (foxMod_->shouldDoStuff(msg))
{
//do stuff
}
}
and there can be many foxMod_ types (one of them instantiated in the Foo constructor by name given in config file) as long as they abide by the common interface of providing a bool shouldDoStuff method. The problem, is that this leads me to define the following:
struct IFoxMod
{
virtual ~IFoxMod() {}
template <class T> shouldDoStuff(T* msg) = 0;
};
for all of the FoxMods to implement (like, class redMountainLogic : public IFoxMod might have it's own way of discerning, when it is appropiate to do stuff).
This is illegal though because one cannot have virtual templates and I'm trying to find a workaround for it. Basically, I need to have dynamic dispatch, but the argument I am passing is a template. I can't think of a workaround.
Virtual function tables don't seem to get along well with template specializations. Not too surprising. VFTs are generally based on declaration order, which doesn't really exist with templates. One solution is to manually recreate VFTs.
Here's an example. It could probably be a little cleaner, but it works.
#include<iostream>
using namespace std;
// Message.h
template<int n>
struct MessageByInt {
typedef int Msg;
};
struct MessageOfHope {
int a;
int b;
static const int id = 0;
};
template<> struct MessageByInt<MessageOfHope::id> { typedef MessageOfHope Msg; };
struct MessageOfDoom {
int b;
int c;
static const int id = 1;
};
template<> struct MessageByInt<MessageOfDoom::id> { typedef MessageOfDoom Msg; };
const int nMessages = 2;
// IFoxMod.h
typedef bool(*callback)(void*);
struct IFoxMod {
callback vtable[nMessages];
template<typename MSG>
bool ShouldDoWork(MSG* msg) {
return vtable[MSG::id](msg);
}
};
template<typename TESTER, int n>
struct filler {
typedef typename MessageByInt<n>::Msg MSG;
typedef typename TESTER::template Tester<MSG> Tester;
static void fill(IFoxMod* impl) {
impl->vtable[n] = reinterpret_cast<callback>(&Tester::ReallyShouldDoWork);
filler<TESTER,n-1>::fill(impl);
}
};
template<typename TESTER>
struct filler<TESTER,-1>{
static void fill(IFoxMod* impl) {
}
};
// RedFox.h
struct RedFoxTester {
template<typename MSG>
struct Tester { // This struct exists to allow partial specialization
static bool ReallyShouldDoWork(MSG* msg) {
return msg->b == 2;
}
};
};
struct RedFoxMod : public IFoxMod {
RedFoxMod() {
filler<RedFoxTester,nMessages-1>::fill(this);
}
};
//Main
main() {
IFoxMod* fm = new RedFoxMod();
MessageOfHope mohb2 = {1, 2};
MessageOfDoom modb2 = {2, 3};
MessageOfHope mohbn2 = {2, 3};
MessageOfDoom modbn2 = {1, 2};
cout << fm->ShouldDoWork(&mohb2) << ", " << fm->ShouldDoWork(&modb2) << endl;
cout << fm->ShouldDoWork(&mohbn2) << ", " << fm->ShouldDoWork(&modbn2) << endl;
}