Conditionally creating members inside a class - c++

Is it possible to do something like:
template <unsigned majorVer, unsigned minorVer>
class Object
{
public:
if constexpr ((majorVer == 1) && (minorVer > 10))
bool newField;
else
int newInt
};
or
template <unsigned majorVer, unsigned minorVer>
class Object
{
public:
if constexpr ((majorVer == 1) && (minorVer > 10))
bool newField;
// Nothing other wise
};
using c++17?
I would like to change the structure of a class based on some condition that can be checked at compile time. Is there any way to achieve this?

You can't use if constexpr for this. You would have to collapse them into one member using something like std::conditional:
std::conditional_t<(majorVer == 1) && (minorVer > 10), bool, int> newField;
Alternatively, you can wrap each of the two kinds of the fields in their own type:
struct A { bool newField; };
struct B { int newInt; };
And either inherit from std::conditional_t<???, A, B> or have one of those as a member.
For the case where you want either a member or nothing, the other case just needs to be an empty type. In C++20, that's:
struct E { };
[[no_unique_address]] std::conditional_t<some_condition(), bool, E> newField;
In C++17 and earlier, you'll want to inherit from this to ensure that the empty base optimization kicks in:
struct B { bool field; };
struct E { };
template <unsigned majorVer, unsigned minorVer>
class Object : private std::conditional_t<some_condition(), B, E>
{ ... };

if-constexpr is about control flow, not about memory layout. Maybe the reflection TS could be a good fit for this. However, untill that is available, you'll need other techniques.
constexpr bool useLegacyInt(unsigned major, unsigned minor)
{
return (majorVer <= 1) && (minorVer <= 10));
}
template<bool>
class ObjectBase
{
book newField;
};
template<>
class ObjectBase<true>
{
int newInt;
};
template <unsigned majorVer, unsigned minorVer>
class Object : public ObjectBase<useLegacyInt (majorVer, minorVer)>
{};
Based on this, you could do some refinements. You don't only influence the members, also the methods. So also setters and getters ... could have a different signature. Protected helper functions could provide a bool API to Object to separate the implementation.
Finally, I would not recommend using a bool, I rather expect an enumeration as this can have multiple values.
Inheriting from an earlier version could also be possible if a new version only extends. And with some default template arguments, you can even do more fancy things.
Be warned, this kind of backwards compatibility could become complex really quickly. Sometimes it's better to just copy the complete code in a legacy version and keep it as is, without interference of the new API. This at the cost of duplicated code.

Related

optional variable declaration in a template

I want to declare member variables in a class template if some condition from template parameters is true. I could use nested class as container, but it is impossible to do explicite specializations in that case.
I'm trying someting like this:
enum class VarPolice { Declare, DontDeclare };
template<VarPolice vp = VarPolice::Declare>
class MyClass
{
struct EmptyStruct {};
struct VarSaverStruct { int MyVar; };
using VarSaver = typename std::conditional<vp == VarPolice::Declare, VarSaverStruct, EmptyStruct>::type;
VarSaver saver;
}
So, I can use MyVar as saver.MyVar
Is there any way to do optional variable declaration without using EmptyStruct that has a size overhead?
C++17 can be used.
Yes, you can have your cake and eat it too. Just inherit from correct type instead, and rely on the empty base optimization.
enum class VarPolice { Declare, DontDeclare };
struct EmptyStruct {};
struct VarSaverStruct { int MyVar; };
template<VarPolice vp = VarPolice::Declare>
class MyClass : std::conditional_t<vp == VarPolice::Declare,
VarSaverStruct, EmptyStruct>
{
};
Standard library implementations rely on it themselves to "store" allocators without taking up space if they are stateless.

Value to type runtime mapping

Consider this code
enum Types
{
t1,
t2
};
struct Base
{
Types typeTag;
Base(Types t) : typeTag(t){}
};
template<typename T>
struct Derived : Base
{
using Base::Base;
T makeT() { return T(); }
};
int main()
{
Base *b = new Derived<std::string>(t1);
auto d = getDerivedByTag(b); // How ??
d->makeT();
return 0;
}
Is it possible to restore Derived type parameter by Base::typeTag value in runtime? Obviously, some external preliminarily prepared mapping is needed, but I can't figure out the exact way.
What you want is basically a reflection that is not (yet) supported in C++. There are ways to simulate it or work around it but they are often verbose and not elegant. I would suggest rethinking your design, particularly your use of auto. It is not supposed to substitute for "any type" as you seem to imply by your code. It is meant as simplification of code when actual type is long or obfuscated (often happens with templates), nested etc. Not when you do not know the type! Because then you cannot really use it, can you.
So what you will have to do in one way or another is check the typeTag directly and continue based on that information. Alternatively you would need to use polymorphism using the Base directly (calling virtual methods propagated to Derived). For type unions you could use boost::variant (if you do not care what type Derived template argument is) or some other framework/library alternative like QVariant in Qt.
I'm not sure if my understanding is correct.
#include "iostream"
enum Types
{
t1,
t2
};
template<typename T>
struct Base
{
typedef T DerivedType;
Types typeTag;
Base(Types t) : typeTag(t){}
DerivedType* operator()() {
return static_cast<DerivedType*>(this);
}
};
template<typename T>
struct Derived : Base<Derived<T>>
{
Derived(Types t): Base<Derived<T>>(t) {}
T makeT() { return T(); }
};
int main()
{
Base<Derived<std::string>> *b = new Derived<std::string>(t1);
auto d = (*b)();
d->makeT();
return 0;
}
https://godbolt.org/g/uBsFD8
My implementation has nothing to do with typeTag.
Do you mean getDerivedByTag(b->typeTag) rather than getDerivedByTag(b)?

Is it possible to use macro conditions with template arguments in C++?

Something like:
template<bool HOLD_MANUFACTURER>
class Computer {
int memory;
int storage;
#if HOLD_MANUFACTURER
char *manufacturer;
#endif
};
I need this to create two variations of the almost-same class, when one variation is a lighter one for performance reasons. I don't want to use a separate class that will wrap the lighter one.
If yes, is it possible to any type (not just bool from the sample code above)? Maybe primitive types only? What about enums?
This code don't work for me, but I hope that I've just missed some little thing.
You can creatively use the empty base optimization in a policy approach to achieve almost what you want:
struct NO_MANUFACTURER {};
struct HOLD_MANUFACTURER { char *manufacturer; };
template <typename ManufacturerPolicy>
class Computer : public ManufacturerPolicy
{
int memory;
int storage;
}
Then instantiate as Computer<HOLD_MANUFACTURER> computer_with_manufacturer;
Not possible, but you can use template specialization and inheritance:
template <bool HoldManufacturer>
class ComputerAdditions
{};
template <>
class ComputerAdditions<true>
{
protected:
char *manufacturer;
public:
// Methods using this additional member
};
template <bool HoldManufacturer = false>
class Computer
: public ComputerAdditions<HoldManufacturer>
{
int memory;
int storage;
public:
// Methods of Computer
}

Multiply inheriting from function objects with a common base (C++)

I have a few function objects that have no member variables. The function objects are very simple in nature. They all inherit from unary_function<> or binary_function<>. For example, a couple of the function objects may be something like this:
struct key_to_hash_method_1 : public binary_function<int, int, int>
{
int operator() (int a, int b) const { /* do something */ }
};
template <typename key_to_hash_method>
struct hash_shrink_method_1 : public binary_function<int, int, int>, public key_to_hash_method
{
int operator() (int a, int b) const { /* do something while utilizing key_to_hash_method */ }
};
/* and more variations of these function objects */
A template class uses these function objects by taking them as template parameters as policies. The template class then inherits from them:
template <typename hash_method>
class foo : public hash_method
{
public:
/* do something while using hash_method as well as using the information provided by binary_function<> to selective compile different functions*/
};
Of course, in the interest of keeping the example simple, the above may not make much sense as far as usefulness goes.
Why am I inheriting instead of using composition? Simply to avoid the empty classes from taking up space. Whether the space saved is minuscule or not is not the point of the question.
As you can see from the above code, binary_function<int, int, int> will be inherited twice, which gives rise to the warning (in VC++ 2008):
Warning 1 warning C4584: 'hash_shrink_method_1<key_to_hash_method>' : base-class 'std::binary_function<_Arg1,_Arg2,_Result>' is already a base-class of 'key_to_hash_method_1' c:\visual studio 2008\projects\defaulttemplatearguments\main.cpp 12
Now generally, in multiple inheritance, this is solved by virtual inheritance; which I want to avoid in this case. What can I do in this situation to remove the warning?
My immediate solution is to not inherit from binary_function<> since I am assuming that key_to_hash_method will be a binary_function. This solution feels a bit like a programmer who does not have access to include guards or pragma once statement. Yes, he can avoid including the header twice, but he'd rather the compiler figure it out for him. I would like the same in this case.
Example code, if you want to try it out:
#include <functional>
using namespace std;
struct key_to_hash_method_1 : public binary_function<int, int, int>
{
int operator() (int a, int b) const { return a + b; }
};
template <typename key_to_hash_method>
struct hash_shrink_method_1 : public binary_function<int, int, int>, public key_to_hash_method
{
int operator() (int a, int b) const { return key_to_hash_method::operator()(1, 2) * 5; }
};
template <typename hash_method>
class foo : public hash_method
{
public:
int test()
{
/* in actual code, this function selectively calls other functions
depending on whether hash_method is unary or binary */
return hash_method::operator()(5, 6);
}
};
int main()
{
foo<hash_shrink_method_1<key_to_hash_method_1> > f;
printf("%i\n", f.test());
}
Your hash_shrink_method_1 doesn't need to inherit from binary_function directly, since you assume that its parameter class key_to_hash_method already does so. You can add a static assertion (std::is_base_of) if you want to be sure; though if you already have C++11, you can do away with the obsolete binary_function anyway.
Language lawyering part.
GCC gives a better warning:
mi.C: In instantiation of ‘hash_shrink_method_1<key_to_hash_method_1>’:
mi.C:18: instantiated from ‘foo<hash_shrink_method_1<key_to_hash_method_1> >’
mi.C:30: instantiated from here
mi.C:12: warning: direct base ‘std::binary_function<int, int, int>’ inaccessible in ‘hash_shrink_method_1<key_to_hash_method_1>’ due to ambiguity
Which is to say, if you inherit from the same base both directly and indirectly, the direct base class cannot be accessed. An attempt to do so will be a compile-time error.
hash_shrink_method_1<key_to_hash_method_1> foo;
binary_function<int, int, int>& bar = foo; // error: ambiguous
There's no way to disambiguate that.
The obvious solution, apart from using virtual inheritance, would be introducing an intermediate layer of inheritance.
template <typename T>
struct wrapped : public T {};
and then
template <typename key_to_hash_method>
struct hash_shrink_method_1 : public wrapped < binary_function<int, int, int> >,
public wrapped <key_to_hash_method >
Now it is possible to disambiguate:
hash_shrink_method_1<key_to_hash_method_1> foo;
foo::wrapped<binary_function<int, int, int> >& intermediate = foo;
binary_function<int, int, int>& bar = intermediate;
OOP/OOD lawyering part.
Please note however that your class now has two operator()(int,int) functions publicly accessible. Which one will be selected depends on how do you access them.
foo<hash_shrink_method_1<key_to_hash_method_1> > f;
hash_shrink_method_1<key_to_hash_method_1>& ff = f;
cout << ff(5,6) << endl; // 15
key_to_hash_method_1& gg = ff;
cout << gg(5,6) << endl; // 11
If this is not what you want, you should not use public inheritance here or perhaps inheritance in general. There's no reason fot inheritance here.
I see two pretty nice approaches.
The first you already mentioned: composition. This is simple to do, and the code looks quite natural.
However, the way your examples run, it looks like your code shouldn't even need to instantiate any these function objects. So you could change the classes to have a static method which does the same thing as operator(), e.g.
struct key_to_hash_method_1 : public binary_function<int, int, int>
{
static int invoke (int a, int b) { return a + b; }
int operator() (int a, int b) const { return a + b; }
};
template <typename key_to_hash_method>
struct hash_shrink_method_1 : public binary_function<int, int, int>
{
static int invoke (int a, int b) { return key_to_hash_method::invoke(1, 2) * 5 }
int operator() (int a, int b) const { return key_to_hash_method::invoke(1, 2) * 5; }
};
Notice that hash_shrink_method_1 doesn't need to inherit from key_to_hash_method_1 any more. Similarly, foo won't need to inherit from hash_method.
(An alternative to using these static methods is to implement the singleton pattern)
A last thought occured to me: since you're using templates to invoke the methods, you don't really need to use binary_function (at least as far as these examples go). If your actual situation is similar to your example code, it might be an idea to just get rid of binary_function.

How to use policy-templates if the types of two templates are linked?

I'm currently writing a class which allows getting and setting interal program options and it should be quite flexible and easy to use.
Specifically, an option is identified by an enum type and a value type, which have a one-on-one relationship. For example, an enum IntType will contains options which have an int type.
I had in mind the following code, but have no idea how to get it working or whether I'm trying to use templates in a way i shouldn't.
enum IntType {OPTION1, OPTION2}
enum StringType { OPTION3, OPTION4}
template<class T, class T2>
class Policy{
public:
T2 getValue(const T& a);
void setValue(const std::string& name, const T2& a);
...
}
class A: public Policy<IntType, int>, public Policy<Stringtype, std::string>, ...{
...
}
Each enum constant has one associated string representation, which is constant, but options are also taken as string input into the program, so I have to be able to deduce from a string which option I should change.
But obviously, this code cannot be used to directly call set or get values without qualifying its full template specialization. So
A* a = ...
a->setValue("intoption", 5);
will not work.
Any pointers on what I should use to get this working?
A partial answer on how to derive at compile time that OPTION1 maps to int and IntType, ... would also be great.
Thanks in advance,
Broes
It is not necessary to pass both the Enum and the type. You can deduce the enum value from the type itself thanks to a traits class:
template <typename T>
struct PolicyTraits;
template <>
struct PolicyTraits<int> { static Enum const value = IntType; }
// ... and so on ...
Your selection is obviously a bit more difficult. For templates to work correctly you need selection based on compile constants, be they constants or types. This requires the names of your options to be constants.
A revised implementation would thus be:
template<class Name, class Type>
class Policy{
public:
Type getValue(Name);
void setValue(Name, Type const&);
...
}
This can be used as:
struct IntOption {};
class A: public Policy<IntOption, int> {};
int main() {
A a;
a.setValue(IntOption(), 3);
}
Also, you might be interested in looking up How Boost does it and perhaps use their library.
Since you are filling the data at runtime, templates are not viable for this design. Runtime polymorphism with virtual function will be a good choice. For example,
class Options; // Say this is the class of interest
class DataType {
public:
virtual Options& getOptions () = 0;
};
class IntType : public DataType {
public:
Options& getOptions (); // implement for 'int' type
};
class StringType : public DataType {
public:
Options& getOptions (); // implement for 'std::string' type
};
Now, class A should contain a pointer to DataType;
class A {
DataType *pData;
public:
void setValue (DataType *p) { pData = p; }
...
};
Usage:
A *a = ...;
a->setValue(new IntType); // take care of heap allocation / stack allocation