C++ created multiple struct with class template - c++

I want to create typesafe structures that are basically identical but have different types so that they require different function signatures.
struct A {
Time t;
void doStuff(const A&);
A getStuff();
};
struct B {
Time t;
void doStuff(const B&);
B getStuff();
};
If I sue a template for the class
template<class T>
struct X {
Time t;
void doStuff(const X&);
X getStuff();
};
how can I make functions typesafe and define function signatures differently for a struct X of type A and a struct X of type B?

Try adding some unused template parameters.
template <int>
struct X{
Time t;
void doStuff(const X&); // You missed return type
X getStuff();
}; // You missed a semicolon
// Great thanks to "aschepler"
And now you can (C++11 syntax)
using A = X<1>;
using B = X<2>;
// typedef X<1> A;
// typedef X<2> B;
The following code will fail, which is what you want:
A a; B b;
a.doStuff(b); // Fail
a = b.getStuff(); // Fail

You could use a combination of Inheritance and template for that.
Following your line of thought, a possible code is:
template <class T> struct X {
int time = 10;
virtual void doStuff(const T&) = 0;
virtual T getStuff() = 0;
};
struct A : X<A>
{
void doStuff(const A& a) {
cout << "Do A stuff" << endl;
}
A getStuff() {
return *this;
}
};
struct B : X<B>
{
void doStuff(const B& value) {
cout << "Do B stuff" << endl;
}
B getStuff() {
return *this;
}
};
Then, testing we have:
int main()
{
A a; B b;
a.doStuff(a); // Ok
b.doStuff(b); // Ok
a.doStuff(b); // fail
b.doStuff(a); // fail
b = b.getStuff(); // Ok
b = a.getStuff(); // fail
return 0;
}

Related

Check for template type parameter, during compile time, for type specific operation

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

SFINAE and number of parameters

I have a template class C<T> which I intend to instantiate with T as some other classes A and B. C<T> has a method foo whose signature I would like to depend on whether T was instantiated as A or B. For example, consider the following code:
#include <iostream>
#include <string>
class A {
public:
void message() {
std::cout << "message with no args" << std::endl;
}
};
class B {
public:
void message(int x) {
std::cout << "message with " << x << std::endl;
}
};
template<typename T>
class C {
private:
T internal;
public:
C(T& x) {
internal = x;
}
void call() {
internal.message();
}
void call(int x) {
internal.message(x);
}
};
int main(int argc, char* argv[]) {
A a;
B b;
C<A> ca(a);
C<B> cb(b);
ca.call();
cb.call(42);
// ca.call(42); ERROR HERE
return 0;
}
This runs correctly. ca.call(42) would raise a compilation error because there is no method A::message(int). However, if I for some reason introduce a method A::message(int) in A, the code may allow calling ca.call(42), which I would like to prevent.
I know that SFINAE techniques would allow to declare a method C::call(T::call_type x) where T::call_type would be a typedef for each intended instantiation of T. However, this only allows me to change the type of the argument of C::call. I would like instead to make the signature (in particular, the number of parameters) of C::call on T. I would thus prevent ca.call(42) from being a valid call even if there is a method A::message(int) in A.
Is there any way to do this?
I don't know all the ins and outs of SFINAE, but what do you think of this?
template <
typename = std::enable_if_t<std::is_same<std::decay_t<T>, A>::value>>
void call() {
internal.message();
}
template <
typename = std::enable_if_t<std::is_same<std::decay_t<T>, B>::value>>
void call(int x) {
internal.message(x);
}
You can use == false too
template <
typename = std::enable_if_t<std::is_same<std::decay_t<T>, B>::value == false>>
You can do this with template specializations:
// Main template used by every other type T.
template<typename T>
class C; // or some other implementation.
// This gets used for T = A.
template<>
class C<A> {
private:
A internal;
public:
C(A& x) {
internal = x;
}
void call() {
internal.message();
}
};
// This gets used for T = B.
template<>
class C<B> {
private:
B internal;
public:
C(B& x) {
internal = x;
}
void call(int x) {
internal.message(x);
}
};
If you don't like that you need to duplicate some common code, then you can have a base class with all those common things and inherit from it in each specialization.

C++14: Generic lambda with generic std::function as class member

Consider this pseudo-snippet:
class SomeClass
{
public:
SomeClass()
{
if(true)
{
fooCall = [](auto a){ cout << a.sayHello(); };
}
else
{
fooCall = [](auto b){ cout << b.sayHello(); };
}
}
private:
template<typename T>
std::function<void(T)> fooCall;
};
What I want is a class member fooCall which stores a generic lambda, which in turn is assigned in the constructor.
The compiler complains that fooCall cannot be a templated data member.
Is there any simple solution on how i can store generic lambdas in a class?
There is no way you'll be able to choose between two generic lambdas at run-time, as you don't have a concrete signature to type-erase.
If you can make the decision at compile-time, you can templatize the class itself:
template <typename F>
class SomeClass
{
private:
F fooCall;
public:
SomeClass(F&& f) : fooCall{std::move(f)} { }
};
You can then create an helper function to deduce F:
auto makeSomeClassImpl(std::true_type)
{
auto l = [](auto a){ cout << a.sayHello(); };
return SomeClass<decltype(l)>{std::move(l)};
}
auto makeSomeClassImpl(std::false_type)
{
auto l = [](auto b){ cout << b.sayHello(); };
return SomeClass<decltype(l)>{std::move(l)};
}
template <bool B>
auto makeSomeClass()
{
return makeSomeClassImpl(std::bool_constant<B>{});
}
I was not able to store std::function<> as a generic lambda in the class directly as a member. What I was able to do was to specifically use one within the class's constructor. I'm not 100% sure if this is what the OP was trying to achieve but this is what I was able to compile, build & run with what I'm suspecting the OP was aiming for by the code they provided.
template<class>
class test {
public: // While testing I changed this to public access...
// Could not get object below to compile, build & run
/*template<class U = T>
static std::function<void(U)> fooCall;*/
public:
test();
};
template<class T>
test<T>::test() {
// This would not compile, build & run
// fooCall<T> = []( T t ) { std::cout << t.sayHello(); };
// Removed the variable within the class as a member and moved it here
// to local scope of the class's constructor
std::function<void(T)> fooCall = []( auto a ) { std::cout << a.sayHello(); };
T t; // created an instance of <Type T>
fooCall(t); // passed t into fooCall's constructor to invoke the call.
}
struct A {
std::string sayHello() { return "A say's Hello!\n"; }
};
struct B {
std::string sayHello() { return "B say's Hello!\n"; }
};
int main() {
// could not instantiate an object of SomeClass<T> with a member of
// a std::function<> type that is stored by a type of a generic lambda.
/*SomeClass<A> someA;
SomeClass<B> someB;
someA.foo();
someB.foo();*/
// Simply just used the object's constructors to invoke the locally stored lambda within the class's constructor.
test<A> a;
test<B> b;
std::cout << "\nPress any key & enter to quit." << std::endl;
char c;
std::cin >> c;
return 0;
}
With the appropriate headers the above as is should compile, build & run giving the output below (At least in MSVS 2017 on Windows 7 64bit did); I left comments where I ran into errors and tried multiple different techniques to achieve a working example, errors occurred as others suggested and I found even more while working with the above code. What I was able to compile, build and run came down to this simple bit of code here without the comments. I also added another simple class to show it will work with any type:
template<class>
class test {
public:
test();
};
template<class T>
test<T>::test() {
std::function<void( T )> fooCall = []( auto a ) { std::cout << a.sayHello(); };
T t;
fooCall( t );
}
struct A {
std::string sayHello() { return "A say's Hello!\n"; }
};
struct B {
std::string sayHello() { return "B say's Hello!\n"; }
};
struct C {
int sayHello() { return 100; }
};
int main() {
test<A> testA;
test<B> testB;
test<C> testC;
std::cout << "\nPress any key & enter to quit." << std::endl;
char c;
std::cin >> c;
return 0;
}
Output:
A say's Hello!
B say's Hello!
100
Press any key & enter to quit
I don't know if this will help the OP directly or indirectly or not but if it does or even if it doesn't it is still something that they may come back to and build off of.
you can simply use a template class or...
If you can get away with using c++17, you could make fooCall's type std::function<void(const std::any&)> and make a small wrapper for executing it.
method 1 : simply use a template class (C++14).
method 2 : seems to mimic the pseudo code exactly as the OP intended (C++17).
method 3 : is a bit simpler and easier to use than method 2 (C++17).
method 4 : allows us to change the value of fooCall (C++17).
required headers and test structures for the demo :
#include <any> //not required for method 1
#include <string>
#include <utility>
#include <iostream>
#include <functional>
struct typeA {
constexpr const char * sayHello() const { return "Hello from A\n"; }
};
struct typeB {
const std::string sayHello() const { return std::string(std::move("Hello from B\n")); }
};
method 1 :
template <typename T>
class C {
const std::function<void(const T&)> fooCall;
public:
C(): fooCall(std::move([](const T &a) { std::cout << a.sayHello(); })){}
void execFooCall(const T &arg) {
fooCall(arg);
}
};
int main (void) {
typeA A;
typeB B;
C<typeA> c1;
C<typeB> c2;
c1.execFooCall(A);
c2.execFooCall(B);
return 0;
}
method 2 :
bool is_true = true;
class C {
std::function<void(const std::any&)> fooCall;
public:
C() {
if (is_true)
fooCall = [](const std::any &a) { std::cout << std::any_cast<typeA>(a).sayHello(); };
else
fooCall = [](const std::any &a) { std::cout << std::any_cast<typeB>(a).sayHello(); };
}
template <typename T>
void execFooCall(const T &arg) {
fooCall(std::make_any<const T&>(arg));
}
};
int main (void) {
typeA A;
typeB B;
C c1;
is_true = false;
C c2;
c1.execFooCall(A);
c2.execFooCall(B);
return 0;
}
method 3 :
/*Note that this very closely resembles method 1. However, we're going to
build off of this method for method 4 using std::any*/
template <typename T>
class C {
const std::function<void(const std::any&)> fooCall;
public:
C() : fooCall(std::move([](const std::any &a) { std::cout << std::any_cast<T>(a).sayHello(); })) {}
void execFooCall(const T &arg) {
fooCall(std::make_any<const T&>(arg));
}
};
int main (void) {
typeA A;
typeB B;
C<typeA> c1;
C<typeB> c2;
c1.execFooCall(A);
c2.execFooCall(B);
return 0;
}
method 4 :
/*by setting fooCall outside of the constructor we can make C a regular class
instead of a templated one, this also complies with the rule of zero.
Now, we can change the value of fooCall whenever we want.
This will also allow us to do things like create a container that stores
a vector or map of functions that each take different parameter types*/
class C {
std::function<void(const std::any&)> fooCall; //could easily be replaced by a vector or map
public:
/*could easily adapt this to take a function as a parameter so we can change
the entire body of the function*/
template<typename T>
void setFooCall() {
fooCall = [](const std::any &a) { std::cout << std::any_cast<T>(a).sayHello(); };
}
template <typename T>
void execFooCall(const T &arg) {
fooCall(std::make_any<const T&>(arg));
}
};
int main (void) {
typeA A;
typeB B;
C c;
c.setFooCall<typeA>;
c.execFooCall(A);
c.setFooCall<typeB>;
c.execFooCall(B);
return 0;
}
Output from Any method
Hello from A
Hello from B

How to get n-th attribute of class in C++

With a normal class. For example:
class A {
public:
int a;
std::string b;
A() {}
~A() {}
}
We can do:
A x;
x.a = 1;
x.b = "hello";
But now I don't want to do like above. I want to access n_index-th attribute of object. For example pseudo like x.get<2>() (or x.set<2>(...)) like x.b.
How can do that? Have any template for that.
Beside if I want code like that
int number = 2;
x.get<number>()
Any problem with constexpr?
I think the closest you can get is using boost::fusion.
An example would be
#include <boost/fusion/adapted.hpp>
#include <boost/fusion/sequence.hpp>
#include <boost/mpl/int.hpp>
#include <iostream>
class A {
public:
int a;
std::string b;
A() {}
~A() {}
};
BOOST_FUSION_ADAPT_STRUCT(A,
(int, a)
(std::string, b)
)
using namespace boost::fusion;
int main()
{
A x;
x.a = 1;
x.b = "hello";
std::cout << at<boost::mpl::int_<0>>(x) << '\n';
std::cout << at<boost::mpl::int_<1>>(x) << '\n';
at<boost::mpl::int_<0>>(x) = 5;
at<boost::mpl::int_<1>>(x) = std::string("World");
std::cout << at<boost::mpl::int_<0>>(x) << '\n';
std::cout << at<boost::mpl::int_<1>>(x) << '\n';
}
If you want to set several values at the same time when you create the object, you could use a multi-parameter constructor. For example, let's imagine you have this:
class A {
public:
int a;
std::string b;
A() {}
~A() {}
};
You could add a constructor that sets a and b:
class A {
public:
int a;
std::string b;
A() {}
A(int a, std::string b) {
this->a = a;
this->b = b;
}
~A() {}
};
That way, you can create your object and set a and b with :
A a = A(1, "hello");
There is no ready-made way of setting the n-th attribute of your object. You could make one, but I would very, very highly recommend that you don't. Like I said above, if you reorder your attributes, then you will have to rework everything.
If you really, really want to make your life very, very, very much harder, a very ugly and error-prone way of doing this would be like :
template<class T>
void A::setNth(int nth, const T& value) {
switch (nth) {
case 1: a = value; break;
case 2: b = value; break;
// You should #include <stdexcept> to use runtime_error, or you could handle the exception in some other way.
default: throw std::runtime_error("A::setNthAttribute : Value of nth is out of bounds.");
}
}
For the getter:
template<class T>
void A::getNth(int nth, T& valueOut) {
switch (nth) {
case 1: valueOut = a; break;
case 2: valueOut = b; break;
default: throw std::runtime_error("A::getNthAttribute : Value of nth is out of bounds.");
}
}
You would use these methods like this:
A a;
a.setNth(1, 2); // put 2 into a
int i;
a.getNth(1, i); // put a into i
Just writing this code send shivers down my spine. Please, never write what I just wrote. Chuck Norris will kill yoU agfh
86sd asdsa dDASD8!4.
What you are considering is in fact possible, but a bit of a headache. I would approach it by creating a template getter and setter for every member that one can set or get, and then having a template method that takes an int and sets or gets the appropriate property. The getters/setters would have to be specialized for the correct type, and throw an error for other types. This method would have to use a switch to return the right member:
class bar {
private:
int a;
std::string b;
template<T>
T getA() {
// error
}
template<T>
T getB() {
// error
}
template<T>
void setA(const T& A) {
// error
}
template<T>
void setB(const T& B) {
// error
}
template <> std::string getB(); // specialization
template <> int getA();
template <> void setB(const std::string&);
template <> void setA(int);
public:
template<T>
T get(int what) {
switch(what) {
case 1:
return getA();
case 2:
return getB();
default:
// handle error here
break;
}
}
template<T>
void set(int what, const T& t) {
switch(what) {
case 1:
return setA<T>(t);
case 2:
return setB<T>(t);
default:
// handle error here
break;
}
}
};
bar b;
b.set<std::string>(2, "foo");
auto str = b.get<std::string>(2);
Here's an elaborate way to accomplish what you want.
#include <iostream>
#include <string>
// A namespace explicitly defined for class A.
namespace A_NS
{
// A template for members of A.
template <int> struct Member;
// Specialization for the first member.
template <> struct Member<1>
{
using type = int;
type var;
};
// Specialization for the second member.
template <> struct Member<2>
{
using type = std::string;
type var;
};
}
class A {
public:
A() {}
~A() {}
template <int N> typename A_NS::Member<N>::type get() const
{
return static_cast<A_NS::Member<N> const&>(members).var;
}
template <int N> void set(typename A_NS::Member<N>::type const& in)
{
static_cast<A_NS::Member<N>&>(members).var = in;
}
private:
// Define a type for the member variables.
struct Members : A_NS::Member<1>, A_NS::Member<2> {};
// The member variables.
Members members;
};
int main()
{
A a;
a.set<1>(10);
a.set<2>("test");
std::cout << a.get<1>() << ", " << a.get<2>() << std::endl;
}
Output:
10, test

How in C++ use templates to call specific members of supplied type

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.