Template classes with template member - c++

I have the following class structure.
class Base {
protected:
template <typename Type>
Type convert(); // no implementation
public:
template <typename Type>
operator Type() {
Type t(convert<Type>());
// log conversion
return t;
}
}
};
class D1: public Base
{
protected:
template <type Type>
Type convert() {
Type t;
// Set t
return t;
}
};
template <typename Type>
class D2: public Base
{
public:
D2(Type v): value(v) {}
protected:
template <typename Type2>
Type2 convert() {
return value;
}
private:
Type value;
}
I am looking for a non-templated class that can be converted into a different type by a type conversion. I do not want to make Base a templated class, as that complicates how it is used.
I would like to force D2 to only allow Type2 and Type to be the same class. As written, if Type can be cast or converted to Type2, the code will work. I am being confused as to whether convert should be declared virtual (the answer appears to be no) and partial nested specializations.
I would like to provide a single specialization in D2 of
template <typename Type>
template <>
Type D2<Type>::convert<Type>() { ... }
but it is clear that this is not allowed.
I also tried
template <>
template <typename Type>
Type D2<Type>::convert<Type>() { ... }
which complained that "prototype for ‘Type D2::convert() const’ does not match any in class ‘D2’
I can't remove the template on convert because it is needed by D1.
Is there a way to get this to work?
At a high level, what I need is to be able to do the following:
Base *b = new D1(/*stuff*/);
int i = *b; // calls D1::convert<int> (a)
b = new D1(/*different stuff*/);
std::string s = *b; // calls D1::convert<std::string> (b)
b = new D2<int>(/* other stuff */);
int j = *b; // calls D2<int>::convert<int> (c)
b = new D2<std::string>(/*still other args*/);
s = *b; // calls D2<std::string>::convert<std::string> (d)
// This should fail as a compile time or link time error
b = new D2<int>(/*... */);
std::string s_fail = *b; // convertable to int, not string
// tries to call D2<int>::convert<std::string>, which is either
// not implemented or has an implementation that fails to compile,
// probably by casting an int to string (e)
The desired behavior is:
(a) Call a method in D1 that returns an int
(b) Call a method in D1 that returns a string
(c) Call a method in D2<int> that returns an int
(d) Call a method in D2<string> that returns a string
(e) Fail as early as possible, ideally at compile time or link time
Is that not possible in C++? I'm happy to rewrite everything except the public interface of Base, D1 not being templated and D2 being templated.
EDIT: Clarify the behavior that I want

Related

Get templated type of Base inside of class that owns instance of Derived

I would like to get the templated type of the base class inside of an object that owns an instance of the derived class. The code snippet below won't work because Base and its ArbitraryType can't be referenced through DerivedString. (line marked with the exclamation point). However, it can most definitely be inferred from the type of its own template (OneOfTheDerivedTypes). In my case, I intend for AnotherObject with a defined template to be inherited from, so I don't want to just hardcode the return type to GetSomethingFromThingy().
// -------------------
// Provided by my API:
// -------------------
template <typename ArbitraryType>
class Base {
virtual void DoSomething(ArbitraryType);
};
template <typename OneOfTheDerivedTypes>
class AnotherObject<OneOfTheDerivedTypes> {
// Other functions that perform useful tasks are here so that
// classes that inherit from AnotherObject need not implement them.
void SomethingMagical();
// A function with a specific return type.
virtual DerivedString::Base::ArbitraryType GetSomethingFromThingy() = 0; /* ! */
protected:
OneOfTheDerivedTypes thingy;
};
// --------------------------------------
// Someone using my API would make these:
// --------------------------------------
class DerivedFloat : public Base<float> {
void DoSomething(float) override;
};
class DerivedString : public Base<string> {
void DoSomething(string) override;
};
class UsefulObject : public AnotherObject<DerivedString> {
// Knows the required return type of GetSomethingFromThingy() without
// needing to specify it as a template. Should throw compile-time error
// if you tried to override with a different return type. In other words,
// forces return type to be string because of use of DerivedString.
string GetSomethingFromThingy() override;
};
One solution to this is specify an additional template arg called ArbitraryType as seen below:
template <typename OneOfTheDerivedTypes, typename ArbitraryType>
class AnotherObject<OneOfTheDerivedTypes> {
virtual ArbitraryType GetSomethingFromThingy() = 0;
protected:
OneOfTheDerivedTypes thingy;
};
class UsefulObject<DerivedString, string> : public AnotherObject<DerivedString, string> {
string GetSomethingFromThingy() override;
};
The programmer then must specify both parameters where OneOfTheDerivedTypes is either DerivedFloat or DerivedString and ArbitraryType is float or string, respectively. Not a good solution because ArbitraryType is completely specified by the choice of OneOfTheDerivedTypes.
I think the extra template (ArbitraryType in AnotherObject) could be avoided by having Base return an instance of ArbitraryType in a public function (call it ReturnInstanceOfArbitraryType()) and use decltype(OneOfTheDerivedTypes::ReturnInstanceOfArbitraryType()) inside of AnotherObject. This seems inelegant because ReturnInstanceOfArbitraryType() is not useful otherwise (and must be public). Is this a case where the proper thing to do is to use a traits class? Is there a better solution? (Still getting the hang of some of this new C++11 stuff). Thanks!
Maybe I've misunderstood your question, but can't you just add a typedef to Base?
template <typename ArbitraryType>
class Base {
virtual void DoSomething(ArbitraryType);
using parameter_type = ArbitraryType;
};
And then you can refer to it:
template <typename OneOfTheDerivedTypes>
class AnotherObject {
// A function with a specific return type.
virtual typename OneOfTheDerivedTypes::parameter_type GetSomethingFromThingy() = 0;
};
And then the override in the derived type will enforce that the return types are the same (or covariant):
class UsefulObject : public AnotherObject<DerivedString> {
string GetSomethingFromThingy() override;
};
You could also add a static_assert if you want a more user-friendly error message:
class UsefulObject : public AnotherObject<DerivedString> {
using base_parameter_type = typename AnotherObject<DerivedString>::parameter_type;
static_assert(std::is_same<string, base_parameter_type>::value,
"mismatched parameter types");
string GetSomethingFromThingy() override;
};
If you can't modify the Base template it's also possible to detect the type using some metaprogramming. First, declare (but don't define) a function that can deduce the type T from Base<T>:
template<typename T> T* detect_base_parameter_type(Base<T>*); // undefined
Now define an alias template which takes one of the derived types as its template parameter, and uses the function above to find the template argument of its base-class:
template<typename DerivedT>
using base_parameter_t = typename std::remove_pointer<
decltype( detect_base_parameter_type(std::declval<DerivedT*>()) )
>::type;
This uses decltype to detect the return type of calling detect_base_parameter_type with a pointer to the derived type. That pointer will convert to a pointer to Base<T> (deducing whatever type T is for DerivedT) and the function's return type will be T*. Then we use remove_pointer to turn that into T.
Now you can use that alias template in your other classes:
template <typename OneOfTheDerivedTypes>
class AnotherObject {
// A function with a specific return type.
virtual base_parameter_t<OneOfTheDerivedTypes> GetSomethingFromThingy() = 0;
};
class UsefulObject : public AnotherObject<DerivedString> {
using base_parameter_type = base_parameter_t<DerivedString>;
static_assert(std::is_same<string, base_parameter_type>::value,
"mismatched parameter types");
string GetSomethingFromThingy() override;
};

Why can I not static_cast a templated object down an inheritance tree?

To be short:
Derived inherits from Base
Holder is templated to contains a pointer to anything
I can tell that an object know as Holder<Base> is a Holder<Derived>.
How can I tell my compiler?
This does not compile:
struct Base { };
struct Derived : Base { };
template <typename T>
struct Holder {
T* point;
int id;
};
Derived* d = new Derived();
Holder<Base> holder {d, 12};
Holder<Derived> specific( static_cast<Holder<Derived>>(holder) );
error: no matching conversion for static_cast from 'Holder<Base>' to 'Holder<Derived>'
This was a naive try for sure. But why does this not work and how should I get the specific holder I need?
Because Holder<Derived> is not derived from Holder<Base>, they are completely unrelated types that just happen to be generated from the same class template.
You can create a Holder<Derived> that contains the right value:
Holder<Derived> specific{ static_cast<Derived*>(holder.point), holder.id };
Or you could add that functionality to the Holder class template itself by adding a converting constructor that does the cast:
template <typename T>
struct Holder {
Holder(T* pt, int id) : point(pt), id(id) { }
template<typename U>
Holder(const Holder<U>& h)
: point(static_cast<T*>(h.point)), id(h.id)
{ }
T* point;
int id;
};
Now your original attempt to use static_cast will work, because there is a valid conversion between them, or you can just write it as:
Holder<Derived> specific( holder );
That statement will compile as long as static_cast<Derived*>(holder.point) compiles.

non-static data member initialization from mother protected field

I have an issue trying to use non-static data member init. in a complex template inheritance chain. I attach a small non-working example:
struct Builder {
template <typename T> T& get() {
return a;
};
float a = 5;
};
struct Base {
Builder a;
};
template <typename T> struct A: public Base {};
template <typename T> struct B: public A<T> {
float& b = (A<T>::a).get<float>(); // Do not work
Builder& builder = A<T>::a;
float& c = builder.get<float>(); // Work
};
struct C: public A<float> {
float& b = a.get<float>(); // Work
};
int main() {
return 0;
}
I'm most interested in class B. I have a compilation error using gcc 4.9.2:
error: expected primary-expression before ‘float’
float& b = (A<T>::a).get<float>(); // Do not work
I don't understand why it does not work as ti does compile if I use the trick two lines below (suffixed by the comment Work) which is basically the same thing.
It also works out of the box if my class is not a template. In this case, I can directly access the protected field by its name without using the syntaxe ParentClass<T>::field.
Do you have any ideas of what I'm doing wrong here?
Thanks a lot for your help!
Here get is a dependent name (it depends on T). You need to explicitly state it's the name of a template :
float& b = A<T>::a.template get<float>();
The second one works because you explicitly "collapse" A<T>::a into a Builder&, which does not depend on T anymore.
The third one works because you inherit from the fully specialized A<float>, which again does not depend on T.

Conversion from child class to parent for templated function pointer

Here is a problem involving inheritance, template classes and function pointers. I'm developing a modular tool, here is a minimal depiction of it.
I have a generic base class that I need to be as general as possible (for reasons unspecified here):
// base class
class Base {
public:
virtual void assess( ) = 0;
};
Then I have a more specialized derived class, that I define as a template:
// derived template class
template <typename T>
class Derived : public Base
{
protected:
T mValue;
public:
void assess( );
T value( ) { return mValue; }
};
// function specialization here
template<>
inline void Derived<int>::assess( )
{
mValue = 3;
}
Some parts are specialized, like the assess() function, as shown above.
Then I have an extra layer of inheritance. The main idea is to have a general assess() function that involves a function pointer with a Base object as argument.
// class specialization for special evaluation through function pointers
template <typename T>
class DerivedFuncPtr : public Derived<T> {
protected:
T (*mFuncPtr)( Base& );
Base *mFuncVar;
public:
DerivedFuncPtr<T>( T (*f)(Base&), Base& variable )
{
mFuncPtr = f;
mFuncVar = variable;
}
void assess( )
{
mFuncVar->assess();
this->mValue = (*mFuncPtr)(*mFuncVar);
}
};
OK, the problem is how to use it. Main source looks like this:
int squared( Derived<int>& );
int squared( Derived<int>& d )
{
int val = d.value();
return val*val;
}
int main (int argc, const char * argv[])
{
Derived<int> object;
object.assess();
cout << object.value() << "\n" ;
DerivedFuncPtr<int> objectFP( squared, object ); // (*)
return 0;
}
I get an error at compilation on line (*)
Candidate constructor not viable: no known conversion from 'int (Derived<int> &)' to 'int (*)(Base &)' for 1st argument
Will I be forced to encapsulate the function pointer into a templated U (*)(Base&) class or am I missing something obvious here?
For the sake of esthetics and because I am really not familiar with most recent C++ evolutions, I'd prefer not to use boost libraries or C++11, but well, if it can't be helped...
Thank you.
DerivedFuncPtr<T>( T (*f)(Base&), Base& variable )
The first argument to your constructor is a pointer to a function that takes a Base& as an argument (and returns a T). That Base& argument to the function pointer doesn't match the argument to squared, which takes a Derived<int>&.
One way to fix this is to make DerivedFuncPtr a class template that take two template arguments, one the typename T you already have, and the other, some other typename that will replace the uses of Base in your data members and constructor.
BTW, you also get an error on mFuncVar = variable; in that constructor. mFuncVar is a pointer, variable is a reference.

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