I want do this:
func(conditionA ? pa1 : pa2, conditionB ? pb1 : pb2, conditionC ? pc1 : pc2);
In C style function, there is no problem. But if func() is a template function, compiler will report errors.
Here pa1 and pa2, ... are different class and have a static method - "convert()". convert() is also declared as inline for performance consideration.
If template cannot solve this problem, there will be a very looooooooooong if-else like below.
if (conditionA)
{
typeA1 a;
if (conditionB)
{
typeB1 b;
if (conditonC)
{
C1 c;
Function(a, b, c);
}
else
{
C2 c;
Function(a, b, c);
}
}
else
{
typeB2 b;
if (conditonC)
{
C1 c;
Function(a, b, c);
}
else
{
C2 c;
Function(a, b, c);
}
}
}
else
{
typeA2 a;
if (conditionB)
{
typeB1 b;
if (conditonC)
{
C1 c;
Function(a, b, c);
}
else
{
C2 c;
Function(a, b, c);
}
}
else
{
typeB2 b;
if (conditonC)
{
C1 c;
Function(a, b, c);
}
else
{
C2 c;
Function(a, b, c);
}
}
}
The result of the conditional operator (that is, the a and b in p ? a : b) must be of the same type. That is, you can't do:
predicate() ? 3.14 : "sdfsd"
Make sure your pa1 and pa2 are compatible types (either they are the same type, inherit from one type, or are cast to compatible types). If you indeed have a convert member function that converts those types to compatible types, then why not just use:
conditionA ? pa1.convert() : pa2.convert()
Finally, it's not sooooo long. You already wrote out the definition. Just keep it generic and move on.
Make pa1 and pa2 inherit from a common base class, and use a reference to that ancestor as the argument type of your (then non-templated) function.
Your basic problem is that the type of an expression must be knowable at compile time.
Is the condition fixed and known at compile time? If so, it will be possible to use a metafunction to choose each parameter:
template <bool B>
struct choose {
typedef X type;
};
template <>
struct choose<false> {
typedef Y type;
};
...
func(choose<a_constant_bool_expr>::type());
(Simplified for a 1-parameter case; for 3 parameters you would define e.g. struct choose1, struct choose2, struct choose3.)
Otherwise, your best option is to derive all types from a common base as John Zwinck suggested. The only alternative to that is a gigantic switch statement or list of ifs.
Actually, maybe this is something that Boost.Variant would be good for?
The problem you have is with the strong typing at compile time and you wish to change the type at runtime. When the template for Function is compiled it needs to know what what types to provide for. You can use different types, you just can't do it all in 1 line.
Is it really that expensive to do a convert() that you would want to do it only if needed in Function?
Stepping away from template ...
Your description has made the length of the method worse than it might seem, you will need to have your a's b's and c's already defined. You could also reduce the conditions into a switch statement.
If you kept the a, b and c as a complete objects and could ask it for the value to be passed to the function.
class a {
p1, p2;
condition;
val value() { return condition? p1.convert, p2.convert };
}
You could make them have an interface that is common for those methods needed in the function. There are several ways to do this, but easiest is if you can change the class for TypeA1 etc. Adding a parent class of something like IConvertable here.
class IConvertable{
public:
~IConvertable(){}
virtual val convert() = 0;
}
And then implementing convert in each class to call the static version of convert.
It's a bit ugly, but you can turn your 3-level nesting into a single switch statement using bits:
const unsigned int caseA = 1 << 0;
const unsigned int caseB = 1 << 1;
const unsigned int caseC = 1 << 2;
switch ((conditionA ? caseA : 0) | (conditionB ? caseB : 0) | (conditionC ? caseC : 0)) {
case 0: func(pa2, pb2, pc2); break;
case caseA: func(pa1, pb2, pc2); break;
case caseB: func(pa2, pb1, pc2); break;
case caseA|caseB: func(pa1, pb1, pc2); break;
case caseC: func(pa2, pb2, pa1); break;
case caseA|caseC: func(pa1, pb2, pc1); break;
case caseB|caseC: func(pa2, pb1, pc1); break;
case caseA|caseB|caseC: func(pa1, pb1, pc1); break;
default: assert(false); // unreachable
}
This split your series of 3 binary decisions into a single 8-way decision, so it's simpler to reason about. Some people may hate it, but I find it quite readable.
Extending on (repeating) what everyone else has said...
This won't work:
template<class TYPE>
inline void Function( TYPE & object )
{
cout << "Function(): " << object.convert() << endl;
}
class A
{
public:
static const char * convert() { return "classA"; }
};
class B
{
public:
static const char * convert() { return "classB"; }
};
int
main(int argc)
{
A a;
B b;
Function( argc>1 ? a : b );
}
As a and b are different types, and the templated Function is being created for you based on the argument type.
But this WILL work:
template<class TYPE>
inline void Function( TYPE & object )
{
cout << "Function(): " << object.convert() << endl;
}
class C
{
public:
virtual const char * convert() = 0;
};
class A : public C
{
public:
static const char * staticConvert() { return "classA"; }
const char * convert() { return A::staticConvert(); }
};
class B : public C
{
public:
static const char * staticConvert() { return "classB"; }
const char * convert() { return B::staticConvert(); }
};
int
main(int argc)
{
A a;
B b;
Function( argc>1 ? (C&)a : (C&)b );
}
Though I really ought to use dynamic_cast...
Function( argc>1 ? dynamic_cast<C&>(a) : dynamic_cast<C&>(b) )
Related
I have the following (kinda pseudo) code, which handles 2 containers of 2 different (but somewhat similiar) types, and I hate having these duplications for addition and deletion (and also 2 searching functions in my real code)
class PureAbstractClass
{
public:
virtual char Func() = 0;
}
class PureOpt1 : PureAbstract
{
public:
virtual int FOption1(A, B, C) = 0; // Notice 'C'
}
class PureOpt2 : PureAbstract
{
public:
virtual int FOption2(A, B, D) = 0; // Notice 'D'
}
class Handler
{
public:
void Add(PureOpt1* arg) { v1.add(arg); }
void Add(PureOpt2* arg) { v2.add(arg); }
// This is implemented using lambda
// Sorry for LINQ syntax, lambdas are too long for pseudo code
void Del1(char c) { arg = v1.find(obj => obj->Func() == c); v1.del(arg); }
void Del2(char c) { arg = v2.find(obj => obj->Func() == c); v2.del(arg); }
void Process(ch, A, B, C, D)
{
o1 = v1.Find(obj => obj->Func() == ch);
if( null == o1 )
{
o2 = v2.Find(obj => obj->Func() == ch);
if( null == o2 )
{
DoSomething();
}
else
{
o2->FOption2(A, B, D);
}
}
else
{
o1->FOption1(A, B, C);
}
}
private:
vector<PureOpt1*> v1;
vector<PureOpt2*> v2;
}
Having Handler be a template class is impossible because of Process().
Is there a more correct way to implement this kind of code?
How to correctly manage 2 containers of different types in a class?
Answer is use only 1 container.
Simplest solution would be to have pure vitual method in base class:
class PureAbstractClass
{
public:
virtual char Func() = 0;
virtual int FOption(A, B, C, D) = 0;
}
then both children override FOption() and ignore parameter they do not need. There could be better solution but you do not provide enough information. Your solution - to keep them in 2 separate containers is probably the worst. As you can see your solution conflicts with inheritance (you remove inheritance and make both children independent classes and nothing would change in your code). Alternatively you can use dynamic_cast, but using it usually shows bad program design:
PureAbstractClass *o = find( ... );
if( !o ) {
DoSomething();
return;
}
if( PureOpt1 *po1 = dynamic_cast<PureOpt1 *>( o ) )
po1->FOption1( A, B, C );
else {
if( PureOpt2 *po2 = dynamic_cast<PureOpt2 *>( o ) )
po2->FOption2( A, B, D );
else
// something wrong object is not PureOpt1 nor PureOpt2
}
Note: it is completely unnecessary for FOption1() and FOption2() to be virtual in this case. And you should not forget to add virtual destructor to the base class.
Alternatively you may use boost::variant and visitor patter, in this case you do not need inheritance as well but you can make your code generic.
If possible have the FOption1/2 be int Func(Data const & data). You then create the data and pass it to it. Data can have the four different pieces of information with C and D being optional. The specific implementation of Func can then process that data as it needs
I have a struct as follows:
struct P
{
enum {INT, FLOAT, BOOLEAN, STRING, ERROR} tag;
union
{
int a;
float b;
bool c;
const char* d;
};
};
I'm using cereal library to serialize this and cereal does not support raw pointers. I'm replacing const char* d with const shared_ptr<char> d. I'm facing 3 issues:
Converting char* to shared_ptr:
char* x = //first element of char array
d = shared_ptr<char> (x); // is this the right way?
Handling assignments like:
string s = "hello";
d = s.c_str(); // how to convert the c_str() to shared_ptr<char>?
From what I've read, shared_ptr seems to handle pointers very different from raw pointers. Will I be able to use this shared_ptr as a character array safely without any side effects?
First thing to say is that you're using a union. Unions in c++ are really hard to get right. Do you really need a union?
If you really need a union, use boost::variant instead. It solves all the complexity for you.
Next, we're using C++ - not C. Let's act like it. Get rid of that const char *. It's a landmine. That's why cereal does not support it. They're doing the right thing. Replace it with what it is. A std::string.
EDIT:
OK. You asked for it. Here is a solution using a discriminated union.
Now, remember I said that unions are hard to get right in c++?
I've been writing c++ almost every day for the past 15 (20?) years. I'm an avid follower of the progress of the standard, I always use the latest tools and I demand that people in my team know the language and the standard library inside out... and I am not yet sure that this solution is fully robust. I would need to spend a day writing tests to be really sure... because discriminated unions are really hard to get right.
EDIT2:
fixed the 'construct from const char*' bug (told you it was hard...)
Are you sure you would rather not use boost::variant?
No? ok then:
#include <iostream>
#include <string>
struct error_type {};
static constexpr error_type as_error = error_type {};
struct P
{
enum {
INT, FLOAT, BOOLEAN, STRING, ERROR
} _tag;
union data
{
data() {}
~data() {} // define a destructor that does nothing. We need to handle destruction cleanly in P
int a;
double b; // use doubles - all calculation are performed using doubles anyway
bool c = false; // provide a default constructor
std::string d; // string or error
} _data;
// default constructor - we must initialised the union and the tag.
P() : _tag { BOOLEAN }, _data {} {};
// offer constructors in terms of the various data types we're storing. We'll need to descriminate
// between strings and errors...
P(int a) : _tag (INT) {
_data.a = a;
}
P(double b) : _tag (FLOAT) {
_data.b = b;
}
P(bool c) : _tag (BOOLEAN) {
_data.c = c;
}
P(std::string s) : _tag(STRING)
{
new (std::addressof(_data.d)) std::string(std::move(s));
}
// provide a const char* constructor... because const char* converts to bool
// more readily than it does to std::string (!!!)
P(const char* s) : P(std::string(s)) {}
P(std::string s, error_type) : _tag(ERROR)
{
new (std::addressof(_data.d)) std::string(std::move(s));
}
// destructor - we *must* handle the case where the union contains a string
~P() {
destruct();
}
// copy constructor - we must initialise the union correctly
P(const P& r)
: _tag(r._tag)
{
copy_construct(r._data);
}
// move constructor - this will be particularly useful later...
P(P&& r) noexcept
: _tag(r._tag)
{
steal_construct(std::move(r._data));
}
// assignment operator in terms of constructor
P& operator=(const P& p)
{
// this line can throw
P tmp(p);
// but these lines will not
destruct();
steal_construct(std::move(tmp._data));
return *this;
}
// move-assignment in terms of noexcept functions. Therefore noexcept
P& operator==(P&& r) noexcept
{
destruct();
_tag = r._tag;
steal_construct(std::move(r._data));
return *this;
}
// don't define swap - we have a nothrow move-assignment operator and a nothrow
// move constructor so std::swap will be optimal.
private:
// destruct our union, using our tag as the type switch
void destruct() noexcept
{
using namespace std;
switch (_tag) {
case STRING:
case ERROR:
_data.d.~string();
default:
break;
}
}
/// construct our union from another union based on our tag
void steal_construct(data&& rd) noexcept
{
switch(_tag) {
case INT:
_data.a = rd.a;
break;
case FLOAT:
_data.b = rd.b;
break;
case BOOLEAN:
_data.c = rd.c;
break;
case STRING:
case ERROR:
new (std::addressof(_data.d)) std::string(std::move(rd.d));
break;
}
}
// copy the other union's data based on our tag. This can throw.
void copy_construct(const data& rd)
{
switch(_tag) {
case INT:
_data.a = rd.a;
break;
case FLOAT:
_data.b = rd.b;
break;
case BOOLEAN:
_data.c = rd.c;
break;
case STRING:
case ERROR:
new (std::addressof(_data.d)) std::string(rd.d);
break;
}
}
public:
// finally, now all that union boilerplate malarkey is dealt with, we can add some functionality...
std::string report() const {
using namespace std::string_literals;
using std::to_string;
switch (_tag)
{
case INT:
return "I am an int: "s + to_string(_data.a);
case FLOAT:
return "I am a float: "s + to_string(_data.b);
case BOOLEAN:
return "I am a boolean: "s + (_data.c ? "true"s : "false"s);
case STRING:
return "I am a string: "s + _data.d;
case ERROR:
return "I am an error: "s + _data.d;
}
}
};
int main()
{
P p;
std::cout << "p is " << p.report() << std::endl;
auto x = P("hello");
std::cout << "x is " << x.report() << std::endl;
auto y = P("goodbye", as_error);
std::cout << "y is " << y.report() << std::endl;
auto z = P(4.4);
std::cout << "z is " << z.report() << std::endl;
return 0;
}
expected results:
p is I am a boolean: false
x is I am a string: hello
y is I am an error: goodbye
z is I am a float: 4.400000
Replacing char * with shared_ptr<char>, as requested by the question title, can be made to compile (with the help of a custom deleter), but it's almost never useful, and will almost certainly not do the right thing in the context of cereal. Since cereal understands standard library types such as strings, why not just use them directly?
Since unions and non-POD types don't really mix, as aptly demonstrated by Richard, you can convert the union into inherited classes with a virtual member function to discriminate the type:
struct P {
enum tag_type {INT, FLOAT, BOOLEAN, STRING, ERROR };
virtual tag_type get_tag() const = 0;
// allow subclsas deletion through base class pointer
virtual ~P() {}
};
struct PInt: public P {
tag_type get_tag() { return INT; }
int a;
};
struct PFloat: public P {
tag_type get_tag() { return FLOAT; }
float b;
};
struct PBool: public P {
tag_type get_tag() { return BOOL; }
bool c;
};
struct PStr: public P {
tag_type get_tag() { return STRING; }
std::string d;
};
struct PError: public P {
tag_type get_tag() { return ERROR; }
};
The code you will end up with is still clunky, but it will handle non-PODs easily and robustly. Using it would boil down to replacing old code that looked like this:
void process(P& x)
switch (x.tag) {
case INT:
// use x._data.a
...
}
}
...with code that uses the get_tag() virtual member to get the tag, and dynamic_cast to access the attributes of the final class:
void process(P& x)
{
switch (x.get_tag()) {
case P::INT:
PInt &intx = dynamic_cast<PInt&>(x);
// ...use intx.a
// case P::FLOAT, etc.
}
}
With this setup, you can use CEREAL_REGISTER_TYPE(Pint), to declare your subclasses to cereal. The library will then use run-time type information to correctly serialize pointers to P.
I have a struct ( can be class ) and is defined in another class as shown
struct A{
somedata_A;
somespecificimplementation_A(someclass *S1);
};
class someclass{
somedata_someclass;
A a;
};
main(){
someclass c1, *c2;
c2 = &c1;
c1.a.somespecificimplementation_A(c2);
}
How do I verify that c2 is indeed a reference for c1? Pardon me for putting up this example as it is obvious that c2 is reference for c1.
Update: A does not store a pointer to someclass
If you don't know nothing about parent, compare member' adresses
void A::somespecificimplementation_A(someclass *S1)
{
if (this == &(S1->a)) {
// parent == S1
} else {
// parent != S1
}
}
Like that:
struct A{
int somedata_A;
int somespecificimplementation_A(someclass *S1){
if ((void*) &(S1->a) == this)
{
std::cout << "S1 is a pointer to myself" << std::endl;
return 1;
}
return 0;
}
};
Assuming struct A has a pointer to c1, you can then take a pointer to c2 and compare pointer values? Similar to what you would do with assignment operator overloads?
Why go the way around and pass a pointer of your class to the nested struct which you then have to test, when you can instead give a reference to the parent by the parent during its construction?
class someclass
{
public:
struct a
{
void foo()
{
parent.doSomething();
}
private:
friend someclass;
a(someclass & parent)
: parent(parent)
{}
someclass & parent;
} a;
someclass() : a(*this) {}
private:
void doSomething()
{
}
};
Although technically unspecified, the following will work on
most modern, general purpose machines:
void A::somespecificimplementation_A( someclass* S1 )
{
char const* s = reinterpret_cast<char const*>( S1 );
char const* t = reinterpret_cast<char const*>( this );
if ( this >= s && this < s + sizeof( someclass ) ) {
// This A is a member of S1
} else {
// This A isn't
}
}
Having said that, I would stress:
This is not specified by the standard. It will work on
machines with a flat, linear addressing, but may fail (give
false positives) on a machine with e.g. segmented memory.
I'd seriously question the design if A needs to know who it
is a member of.
And if A really does need this information, it really should store
a pointer to someclass, which is passed in to its constructor, so that the dependency is manifest.
For a constructor with multiple arguments...
For example:
class C {
public:
C(int a=1, int b=2){ cout << a << ", " << b << "\n"; }
}
int main(){
C a(10), b = 20;
}
output:
10, 2
20, 2
How do I just assign value to the 2nd parameter? So that I can get "1, 20" without knowing the default values? Or is that that I must always assign value to the argument that precedes before I can use the arguments behind?
And how do I implicitly assign all the parameters? If I can't do that, why? For the above example (as I am new to C++), I once thought I would get "10, 20" as output instead.
Or is that that I must always assign value to the argument that precedes before I can use the arguments behind?
Yes. Otherwise, how is the compiler supposed to know which argument should be used for which parameter?
However, there are ways to accomplish this. For example,
struct C {
enum { DefaultA = 1, DefaultB = 2 };
C(int a = DefaultA, int b = DefaultB) { /* ... */ }
};
C object(C::DefaultA, 20);
Or, if you have a lot of parameters with different "defaults:"
struct CParams {
int a, b;
CParams() : a(1), b(2) { }
};
struct C {
C(CParams x) { /* ... */ }
};
CParams params;
params.b = 20;
C object(params);
C++ doesn't support named arguments. You have to specify the first one.
Also, the variable name b from the main function is completely separate from the b in the constructor definition. There's no relationship whatsoever implied by the naming.
I had the same thought (Convienient C++ struct initialisation -- perhaps you find something you like better there) some time ago, but just now, reading your question, I thought of a way to actually accomplish this. But it is quite some extra code, so the question remains if it is actually worth it. I just implemented it very sketchy and I am not proud of my choice of names (I usually don't use _ but it's late). Anyway, this is how you can do it:
#include <iostream>
struct C_members {
int a;
int b;
C_members(int _a, int _b) : a(_a), b(_b) {}
};
class C_init {
public:
virtual C_members get(C_members init) const {
return init;
}
};
class C_a : public C_init {
private:
int a;
public:
C_a(int _a) : a(_a) {}
C_members get(C_members init) const {
init.a = a;
return init;
}
};
class C_b : public C_init {
private:
int b;
public:
C_b(int _b) : b(_b) {}
C_members get(C_members init) const {
init.b = b;
return init;
}
};
class C : private C_members {
private:
static const C_members def;
public:
C(C_init const& ai = C_init(), C_init const& bi = C_init()) : C_members(ai.get(bi.get(def)).a, bi.get(ai.get(def)).b) {
std::cout << a << "," << b << std::endl;
}
};
const C_members C::def(1,2); // default values
// usage:
int main() {
C c1(C_b(77)); // 1,77
C c2(C_a(12)); // 12,2
C c3(C_b(5),C_a(6)); // 6,5
return 0;
}
There is a lot of stuff that can be improved (with templates (for code reduction) and with const refs in the get method), but you get the idea.
As a bonus feature, you almost have the pimpl idiom implemented (very little effort is necessary to extend this to an actual pimpl design).
Usually in OOP, every object instance holds (and represents) a state.
So the best way is to define an accessor functions such as
void setB(int newBvalue);
and also to hold b as a private member.
if "b" is shared among all the instances of the same object, consider to save a static variable.
You're given two structs. One of type 'A', another of type 'B'.
The one of type 'B' has a struct of type 'A' in it. So something like this:
struct A {
void print_stuff(A * a){ puts("From A"); }
};
struct B {
A a_part;
char * s;
void print_stuff(B * b){
printf("From B\n\t%s\n", b->s);
}
};
B * B_new(char * str) {
B * b = (B*)malloc(sizeof(struct B));
b->s = strdup(str);
return b;
}
You want to be able to call struct B's 'print_stuff' function, even with code like this:
A * aptr = (A*) B_new("foo");
aptr->print_stuff(aptr);
You are NOT allowed to use inheritance, C++ containers or classes. Struct B MUST have a_part.
How would you write your code so that regardless of the type of the pointer, the correct print_stuff function is called (in this case, if a pointer to a struct of type B was casted to A*, how would you guarantee that the print_stuff function in B is called)?
You could make print_stuff a function pointer, but then you need to manually hook it up to the correct function. In this case though, you're just replicating C++ inheritance mechanisms so it's pointless.
The A object can't automatically know where it's contained, or if it's contained at all.
So the bottom line is, just use C++ inheritance.
This is really horrible. But yes, there is a way to do it. Put a bool field in A, and in the same place in B, to indicate the real type. The code below should give you an appreciation of C++ (and really shouldn't be used for any other purpose).
struct A {
bool isB;
A()
{
isB=false;
}
void print_stuff(A * a);
};
struct B {
bool trueB;
A a_part;
char * s;
B()
{
isB=true;
}
void print_stuff(B * b){
printf("From B\n\t%s\n", b->s);
}
};
void A::print_stuff(A * a)
{
if(isB)
{
B* b = (B*)(this);
b->print_stuff(b);
}
else
puts("From A");
}
B * B_new(char * str) {
B * b = (B*)malloc(sizeof(struct B));
b->s = strdup(str);
b->trueB=true;
return b;
}