I thought my problem was answered by this, but I can't get the following to compile:
#include <string>
template<class C>
class tKeySet {
protected:
bool set;
static const std::string key;
};
template<class C, typename T>
class tKeySetType : private tKeySet<C> {
protected:
T m_val;
};
template<class C>
class tKeySetString: private tKeySetType<C, std::string> {
public:
tKeySetString<C>& operator=(const std::string &str) {
this->set = true;
this->m_val = str;
return *this;
}
};
class foo : private tKeySetString<foo> { };
template<> const std::string tKeySet<foo>::key = "foo key";
int main(void) {
foo f;
f = std::string("foo");
return 0;
}
How can I make the assignment operator in tKeySetString<C> work with std::string?
foo privately inherits from tKeySetString<foo>, which means that operator= will not be part of its public interface.
You can bring it in by writing
public:
using tKeySetString::operator=;
in the definition of foo.
Related
I am trying to understand the behavior of "Type Erasure" by using std::make_shared. The basic idea is to use a class Object to wrap some different classes, such as class Foo and class Bar.
I write the following code, and it does work.
// TypeErasure.cpp
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class Base
{
public:
virtual ~Base() {}
virtual std::string getName() const = 0;
};
template< typename T >
struct Derived : Base
{
public:
explicit Derived(const T&& t) : objD(t) {}
std::string getName() const override
{
return objD.getName();
}
private:
T objD;
};
class Object
{
public:
template <typename T>
explicit Object(T&& t)
: objPtr(std::make_shared<Derived<T>>(std::forward<T>(t))) {}
std::string getName() const
{
return objPtr->getName();
}
std::shared_ptr<const Base> objPtr;
};
void printName(std::vector<Object> vec)
{
for (auto v: vec) std::cout << v.getName() << std::endl;
}
class Bar
{
public:
std::string getName() const
{
return "Bar";
}
};
class Foo
{
public:
std::string getName() const
{
return "Foo";
}
};
int main()
{
std::vector<Object> vec{Object(Foo()), Object(Bar())};
printName(vec);
}
but when I change "struct Derived : Base" into "class Derived : Base", it shows the following error.
error: no matching function for call to 'std::shared_ptr::shared_ptr(std::shared_ptr)'|
The code is as following.
// TypeErasure.cpp
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class Base
{
public:
virtual ~Base() {}
virtual std::string getName() const = 0;
};
template< typename T >
class Derived : Base
{
public:
explicit Derived(const T&& t) : objD(t) {}
std::string getName() const override
{
return objD.getName();
}
private:
T objD;
};
class Object
{
public:
template <typename T>
explicit Object(T&& t)
: objPtr(std::make_shared<Derived<T>>(std::forward<T>(t))) {}
std::string getName() const
{
return objPtr->getName();
}
std::shared_ptr<const Base> objPtr;
};
void printName(std::vector<Object> vec)
{
for (auto v: vec) std::cout << v.getName() << std::endl;
}
class Bar
{
public:
std::string getName() const
{
return "Bar";
}
};
class Foo
{
public:
std::string getName() const
{
return "Foo";
}
};
int main()
{
std::vector<Object> vec{Object(Foo()), Object(Bar())};
printName(vec);
}
What is the root cause of this error?
Is it about the difference between class and struct?
Is it because class is a reference and struct is a value?
The only real difference between a class and a struct in C++ is that, for a struct, the default member access and inheritance is public, whereas, for a class, the default is private.
So, to make your code work for the class Derived template, just make its inheritance of Base public:
template< typename T >
class Derived : public Base { // public inheritance
public:
//...
Such public inheritance gives the Derived class access to the Base class constructors.
Alternatively, to make your struct template case fail – most likely with the exact same error message(s) – you can make its inheritance of Base private:
template< typename T >
struct Derived : private Base { // private inheritance - fails to compile!
public:
//...
I have a parent class Obj with empty virtual function cmp
class Obj{
public:
virtual int cmp(const Obj& val) = 0;
...
};
I am trying to define that function in the subclass MyString, but instead of const Obj& as argument, i use const MyString& which probably occures the error "Emprty virtual function Obj::cmp has no redifinition"
class MyString : public Obj{
private:
...
public:
virtual int cmp(const MyString& val){
... using private values of MyString
}
};
So how can i solve that, if i have 3-4 subclasses which uses their own variables in that function
An example that comes to my mind is the curiously recurring template pattern. It goes like this:
#include <iostream>
#include <ostream>
template <typename T>
struct Base
{
virtual int cmp(T const &) = 0;
};
struct First : Base<First>
{
virtual int cmp(First const &);
};
int First::cmp(First const &)
{
std::cout << "First\n";
return 1;
}
struct Second : Base<Second>
{
virtual int cmp(Second const &);
};
int Second::cmp(Second const &)
{
std::cout << "Second\n";
return 2;
}
int main()
{
Base<First>* f1 = new First();
Base<First>* f2 = new First();
Base<Second>* s = new Second();
f1->cmp(*dynamic_cast<First*>(f2)); // if this will throw, use RAII instead of deletes below
// f1->cmp(*dynamic_cast<Second*>(f2)); error: cannot convert Second to First
delete f1;
delete f2;
}
If you want to use overriding you have to define method in subclasses as it is in base class and can't change parameters of virtual function. In method of subclass you can cast to a type you need.
class Obj
{
public:
virtual int cmp(const Obj& val) = 0;
...
};
class MyString : public Obj
{
private:
...
public:
int cmp(const Obj& val)
{
// cast val to MyString& (you can use dynamic_cast)
... using private values of MyString
}
};
Also you can use overloading. In this case you don't need virtual method in base class.
class Obj
{
public:
int cmp(const Obj& val)
{
// implementation for Obj
}
...
};
class MyString : public Obj
{
private:
...
public:
int cmp(const MyString& val)
{
... using private values of MyString
}
};
I've tried to use c++ properties and now I'm stuck with this:
class a {
protected:
// wikipedia https://en.wikipedia.org/wiki/Property_(programming)#C.2B.2B
template<class s, typename t>
class getonly {
protected:
friend s;
t value;
t set(); // operator =...
public:
t get(); // t operator...
};
};
class b : public a {
public:
getonly<b, int> id;
};
What I want is something like this, where getonly is parametrized by only the typename (int), and not the class (b):
class b : public a {
public:
getonly<int> id;
};
Is this possible? Can anyone help me?
It appears that you want a data member that can be read by any code, but that can only be changed by the containing class.
The attempt at providing friend-ship via template would not have compiled prior to C++11. It means that this code can not be easily modified to work with a C++03 compiler (with C++03 one could express the access restriction on modification via e.g. an owner credential argument to a setter). However, that concern becomes less significant every day.
Here's your code modified to compile, and with the inheritance changed from public to private (it doesn't make much sense to say that b "is-an" a):
class a {
protected:
// wikipedia https://en.wikipedia.org/wiki/Property_(programming)#C.2B.2B
template<class s, typename t>
class getonly {
protected:
friend s;
t value_;
public:
auto get() const -> t const& { return value_; }
operator t const& () const { return value_; }
getonly( t v ): value_( v ) {}
};
};
class b : private a {
public:
getonly<b, int> id;
void set_id( int x ) { id.value_ = 2*x; }
b(): id( 42 ) {}
};
#include <iostream>
auto main() -> int
{
using namespace std;
b obj;
cout << obj.id << endl;
obj.set_id( 333 );
cout << obj.id << endl;
}
So first off, this can be done with CRTP
template<typename s>
class a {
protected:
// wikipedia https://en.wikipedia.org/wiki/Property_(programming)#C.2B.2B
template<typename t>
class getonly {
protected:
friend s;
t value;
t set(); // operator =...
public:
t get(); // t operator...
};
};
class b : public a<b> {
public:
getonly<int> id;
};
But since you mentioned inheritance, are you aware that friend declarations are not inherited? If that is your goal, then there is a more elegant solution - do not use the property as a base class but as traits:
template<typename T, typename F>
class property_impl
{
friend F;
private:
T value_;
protected:
void set(T value)
{
value_ = value;
}
public:
T get()
{
return value_;
}
};
template<typename F>
class property_traits
{
template<typename T> using property = property_impl < T, F > ;
};
class foo : public property_traits < foo >
{
public:
property<int> id_;
};
class bar : public foo, public property_traits < bar >
{
public:
property<int> another_id_;
void doStuff(foo f)
{
auto value = f.id_.get();
// f.id_.set(5); <-- fails since friend is not inherited
}
};
int main(int argc, char** argv)
{
foo f;
auto value = f.id_.get();
bar b;
auto another_value = b.another_id_.get();
b.doStuff(f);
return 0;
}
This will give you the ability to inherit and specialize on each class that needs a property while retianing the fact, that only the class type used in specialization is able to modify the value.
Again, maybe you want that, I am not sure.
During compilation the code below in clang i have warning (in vc++ it works fine):
warning : explicit specialization of 'Helper' within class scope is a
Microsoft extension [-Wmicrosoft]
#include <stdio.h>
#include <string>
enum class Car { BMW };
class C
{
static void Method() { puts("inner");}
};
template<typename T>
class BaseClass
{
private:
template<typename V>
struct Helper;
template<>
struct Helper<Car>
{
typedef C InnerType;
static const char* Name() { return "Car"; }
};
typedef Helper<T> Info;
typedef typename Info::InnerType InnerType;
private:
T v;
protected:
BaseClass()
{ }
public:
T Value() const { return v; }
std::string Name() const { return Info::Name(); }
static void Print() { InnerType::Method(); }
};
class MyCar : public BaseClass<Car>
{
public:
MyCar() : BaseClass() {}
};
int main()
{
MyCar a;
printf("%s\n", a.Name().c_str());
// a.Print();
}
I have tried to move the specialization of Helper class outside BaseClass to be compatible with standard:
template<> template<>
struct BaseClass<Car>::Helper<Car>
{
typedef C InnerType;
static const char* Name() { return "Car"; }
};
But now I have compilation error:
error: implicit instantiation of undefined template 'BaseClass::Helper'
If I remove the line: typedef typename Info::InnerType InnerType; (and related usage in function Print) then everything works fine.
Is it possible to fix this error ? I would like to keep my Helper class as private.
You can do it like this:
#include <stdio.h>
#include <string>
enum class Car { BMW };
class C
{
static void Method() { puts("inner");}
};
template<typename T>
class BaseClass
{
private:
template<typename V>
struct Helper;
template<typename V>
using Info = Helper<V>;
template<typename V>
using InnerType = typename Info<V>::InnerType;
private:
T v;
protected:
BaseClass()
{ }
public:
T Value() const { return v; }
std::string Name() const { return Info<T>::Name(); }
static void Print() { InnerType<T>::Method(); }
};
template<> template<>
struct BaseClass<Car>::Helper<Car>
{
typedef C InnerType;
static const char* Name() { return "Car"; }
};
class MyCar : public BaseClass<Car>
{
public:
MyCar() : BaseClass() {}
};
int main()
{
MyCar a;
printf("%s\n", a.Name().c_str());
//a.Print();
}
(gcc 5.1/clang 3.6, -std=C++11)
The program prints "Car".
Following does not work:
std::vector<IRule*> vec;
RuleRangeDouble *rule = new RuleRangeDouble(0, 100);
vec.push_back(rule);
Now how can a make a vector of different rules? I know, I have to use pointers... But what else do I have to do to get this working? How can I change my base structure to get this work?
I use an Interface like the following:
// Interface
template <typename T>
class IRule
{
public:
virtual bool isValid(T value) = 0;
};
And my example class looks like this:
class RuleRangeDouble : public IRule<double>
{
private:
double min;
double max;
public:
bool isValid(double value)
{
....
};
};
The vector needs to be a vector of an actual type, for example std::vector<IRule<double>*>. Irule on its own is not a type, it is a class template. So you would need
std::vector<IRule<double>*> vec;
RuleRangeDouble *rule = new RuleRangeDouble(0, 100);
vec.push_back(rule);
If the template parameter is not part of the interface, you can introduce a common base class. Don't forget to give it a virtual destructor:
class IRule
{
public:
virtual bool isValid(T value) = 0;
virtual ~IRule() {}
};
template <typename T>
class Rule : public IRule
{
.....
};
class RuleRangeDouble : public Rule<double>
{
....
};
Then your original use case sample would work:
std::vector<IRule*> vec; // IRule really is a type now
RuleRangeDouble *rule = new RuleRangeDouble(0, 100);
vec.push_back(rule);
You can implement something like getBestValidValue()in several ways. One is to define a special general (but non-template) return type to be used for getBestValidValue() and also as argument type for isValid(value) (juanchopanza's answer was faulty here):
class ValueType
{
enum { is_int, is_double } my_type; // add more if you want
union { my_int; my_double; }; // union only works for simple types
public:
// implicit construction from allowed types
ValueType(int x) : my_type(is_int), my_int(x) {}
ValueType(double x) : my_type(is_double), my_double(x) {}
// use SFINAE for is<type>() function
template<typename T>
typename std::enable_if<std::is_same<T,int>::value,bool>::type
is() const { return my_type==is_int; }
template<typename T>
typename std::enable_if<std::is_same<T,double>::value,bool>::type
is() const { return my_type==is_double; }
// implicit type conversion to allowed types
// note: does not assert(is<T>())
operator int() { return my_int; }
operator double() { return my_double; }
};
class IRule
{
public:
virtual bool isValid(ValueType const&) const = 0; // fixed bug in juanchopanza's answer
virtual ValueType getBestValidValue() const = 0; // return any type of value
virtual ~IRule() {}
};
template<typename T>
class Rule : public IRule
{
protected:
virtual bool valid(T) const = 0;
virtual T bestValidValue() const = 0;
public:
bool isValid(ValueType const&value) const
{
return value.is<T>()
&& valid(value); // implicit type conversion to T
}
ValueType getBestValidValue() const
{
return bestValidValue(); // implicit construction of ValueType
}
....
}