I am trying to implement a general value class in C++ that can contain integer, float, and fractions, etc. So I wrote an interface value_interface and had int wrapped up in int_wrapper to inherit from the interface.
However, value(3) will not initialize a value object, because even if 3 is convertable to int_wrapper, which is convertable to value_interface, value_interface is not directly convertable to value. Is there a way to make value(3) possible? Or is there a better way to do this?
#include <string>
class value_interface {
public:
virtual std::string to_string() const = 0;
virtual ~value_interface() {}
};
class value {
std::shared_ptr<value_interface> d_ptr_;
public:
value(value_interface* x) { d_ptr_ = std::unique_ptr<value_interface>(x); }
std::string to_string() const { return d_ptr_->to_string(); }
};
class int_wrapper : public value_interface {
int val_;
public:
int_wrapper(const int val) : val_(val) {}
operator int() const { return val_; }
std::string to_string() const override { return std::to_string(val_); }
friend value operator+(int_wrapper x, int_wrapper y);
};
int main() {
value a = 3; // Error C2440 'initializing': cannot convert from 'int' to 'value'
int_wrapper b = 3; // ok
value_interface& c = static_cast<value_interface&>(b); // ok
value d = &c; // ok
return 0;
}
Create a make_value templated function with specialisations for each class. e.g:
template < typename T >
value make_value( const T& t );
template <>
value make_value< int >( const int& i )
{
return value{ std::make_shared< int_wrapper >( i ) };
}
Alternatively you can template the value constructor which will allow you to do value v = 3 directly:
class value {
std::shared_ptr<value_interface> d_ptr_;
public:
value(value_interface* x) { d_ptr_ = std::unique_ptr<value_interface>(x); }
template < typename T >
value( const T& t );
std::string to_string() const { return d_ptr_->to_string(); }
};
template <>
value::value< int >( const int& i )
:d_ptr_(std::make_shared<int_wrapper>(i))
{
}
Related
I have a template:
template<typename T>
struct Parameter {
T value;
std::string name;
Parameter(std::string name, T value) : name(name), value(value){}
void fix() {
// Fix this->value (make this->value const)
}
void print() { std::cout << value << std::endl; }
};
and I would like at some point after initialization to 'const-ify' the value variable
std::string name = "variance";
double var = 1.0;
Parameter<double> variance(name, var);
variance.print();
variance.fix();
variance.value = 2.3; // Not Allowed, throws error
Is it possible to do so and how?
If you want to maintain the same interface, and marshalling access to value through accessors is something you want to avoid, then you could isolate the "fixable" feature in its own dedicated type that implicitly converts to/from T:
template<typename T>
class fixable {
bool fixed_ = false;
T val_;
public:
fixable() = default;
fixable(T v) : val_(v) {}
fixable(const fixable&) = default;
fixable(fixable&&) = default;
operator const T&() const {
return val_;
}
fixable& operator=(const T& v) {
if(fixed_ ) {
throw std::runtime_error("Fixable has been fixed");
}
val_ = v;
return *this;
}
void fix() {
fixed_ = true;
}
};
You would then replace the T member with a fixable<T> within Parameter:
template<typename T>
struct Parameter {
fixable<T> value;
std::string name;
Parameter(std::string name, T value) : name(name), value(value){}
void fix() {
value.fix();
}
void print() { std::cout << value << std::endl; }
};
The main function from your question can remain exactly as-is.
You can use something like this:
Similar to abowe answer but with boolean inside the Parameter struct
template<typename T>
struct Parameter {
Parameter(std::string name, T value) : name(name), value(value), bFixed(false) {}
void fix() {
bFixed = true;
}
void print() { std::cout << value << std::endl; }
Parameter& operator=(const T& oValue)
{
if (bFixed)
{
throw std::runtime_error("Error fixed value..");
}
value = oValue;
return *this;
}
std::string name;
private:
bool bFixed;
T value;
};
int main()
{
std::string name = "variance";
double var = 1.0;
Parameter<double> variance(name, var);
variance.print();
variance.fix();
variance = 2.3; // Not Allowed, throws error
}
You cannot change a member variable from const to non-const. However, you can create a new object in which it is const. For example:
template<typename T>
struct example {
T value;
example<T const> fix() && {
return {value};
}
};
int main(){
auto x = example<int>{1};
x.value = 4; // OK
auto y = std::move(x).fix();
y.value = 7; // error: assignment of read-only member
}
The presence of && forces the use of std::move which makes it obvious that x should no longer be used.
I have an abstract class say A which is implemented by a template class say B, B is specialized for a vector type that implements a copy constructor and a copy assignment operator, but when I compile i get the error: static assertion failed: result type must be constructible from value type of input range. Declaring a virtual copy assignment in the abstract class does not help, as the signature there is: A & operator=(const A &); but in B it is implemented for type B so the signatures do not match.
Why I have this weird hierarchy?
Because I am trying to implement a json parsing library, I need to have a container that can store string, number, bigint, boolean and array types, so I implemented the hierarchy to achieve type erasure, the template type is for these 5 types and need to specialize only for string and vector types.
Actual hierarchy (minimal reproducible example):
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <iostream>
class BasicJsonType {
public:
virtual std::string toString() const = 0;
virtual void setNull() = 0;
// copy assignment method
// virtual BasicJsonType& operator= (const BasicJsonType &value) = 0;
~BasicJsonType() = default;
};
template<typename T>
class BasicJsonTypeInterface: public BasicJsonType {
protected:
bool empty = true;
public:
virtual const T& get() = 0;
virtual void set(const T&) = 0;
};
namespace json {
// json::array is defined as
using array = std::vector<BasicJsonType>;
}
template <typename T>
class JsonValue {
T x;
public:
virtual std::string toString() {
return "";
}
virtual const T & get() {
return this->x;
}
virtual void set(const T &value) {
this->x = value;
}
};
template<>
class JsonValue<json::array>: public BasicJsonTypeInterface<json::array> {
std::shared_ptr<json::array> array;
public:
JsonValue() = delete;
JsonValue(const JsonValue<json::array> &value): JsonValue(*(value.array)) {
std::cout << "const JsonValue<json::array> &";
}
JsonValue(const json::array &array) {
std::cout << "const json::array &";
// error
this->array.reset(new json::array(array));
}
JsonValue(JsonValue<json::array> &&value): JsonValue(static_cast<json::array &&> (*(value.array)))
{ std::cout << "const JsonValue<json::array> &"; }
JsonValue(json::array &&array) {
this->array.reset(new json::array(std::move(array)));
this->empty = false;
}
virtual void setNull() { }
virtual const json::array &get() {
return *(this->array);
}
virtual void set(const json::array &value) {
this->array.reset(new json::array(value));
}
};
int main() {}
I created the interface type since I wanted to implement the get, set methods for all the types and irrespective of the type.
I searched for the error, and what I found is I am missing a copy function for the BasicJsonType, like what it suggests here.
There maybe some design flaws in this, since it is my first try with anything of practical use with c++, I am targeting for c++11.
std::vector<BasicJsonType>;
This is a useless type.
BasicJsonType is an abstract class. Abstract classes are not value types. std::vector stores value types.
std::vector expects regular types (or semiregular if you don't need copy). Abstract types are NOT regular types.
There are a number of ways to have polymorphic regular types, but they all take work or 3rd party libraries.
A minor issue:
~BasicJsonType() = default;
this should be virtual.
...
There are a number of ways to approach your problem of getting a regular type to store in std::vector.
Store unique_ptr<BasicJsonType> in your vector. This permits moving but not assignment*.
Implement a value_ptr (based off unique ptr) that understands how to (virtually) clone its contents when copied.
Implement a cow_ptr that uses a shared ptr under the hood for immutable data, and does a copy-on-write.
Create an any_with_interface based off std::any that guarantees the stored value matches an interface, and provides operator-> and * that returns that interface.
Store a std::variant of the various kinds of json concrete types. Write a helper function to get the abstract interface (if you need it).
As your set of supported types is closed (there are only so many json types), #5 is probably easiest.
class BasicJsonType {
public:
virtual std::string toString() const = 0;
virtual void setNull() = 0;
virtual bool isNull() const = 0;
protected: // no deleting through this interface
~BasicJsonType() = default;
};
// if we find this overload, remember to implement
// your own to_json_string for the type in question
template<class T>
std::string to_json_string( T const& ) = delete;
std::string to_json_string( std::string const& s ) { return s; }
std::string to_json_string( double const& d )
{
std::stringstream ss;
ss << d;
return ss.str();
}
template <typename T>
class JsonValue:public BasicJsonType {
public:
JsonValue() = default;
JsonValue(JsonValue const&) = default;
JsonValue(JsonValue &&) = default;
JsonValue& operator=(JsonValue const&) = default;
JsonValue& operator=(JsonValue &&) = default;
JsonValue( T t ):value(std::move(t)) {}
std::optional<T> value;
std::string toString() const final {
if (value)
return to_json_string(*value);
else
return "(null)";
}
bool isNull() const final {
return !static_cast<bool>(value);
}
void setNull() final {
value = std::nullopt;
}
};
template<class T>
JsonValue(T)->JsonValue<T>;
you create a free function to_json_string for each T you pass to JsonValue; if you don't, you get a compile-time error.
The remaining tricky part is making a variant containing a vector of a type depending on the same variant.
struct json_variant;
using json_array = std::vector<json_variant>;
struct json_variant :
std::variant< JsonValue<double>, JsonValue<std::string>, JsonValue<json_array> >
{
using std::variant< JsonValue<double>, JsonValue<std::string>, JsonValue<json_array> >::variant;
std::variant< JsonValue<double>, JsonValue<std::string>, JsonValue<json_array> > const& base() const { return *this; }
std::variant< JsonValue<double>, JsonValue<std::string>, JsonValue<json_array> >& base() { return *this; }
};
BasicJsonType const& getInterface( json_variant const& var )
{
return std::visit( [](auto& elem)->BasicJsonType const& { return elem; }, var.base());
}
BasicJsonType& getInterface( json_variant& var )
{
return std::visit( [](auto& elem)->BasicJsonType& { return elem; }, var.base());
}
std::string to_json_string( json_array const& arr )
{
std::stringstream ss;
ss << "{";
for (auto&& elem:arr)
{
ss << getInterface(elem).toString();
ss << ",";
}
ss << "}";
return ss.str();
}
and test code:
JsonValue<json_array> bob;
bob.value.emplace();
bob.value->push_back( JsonValue(3.14) );
bob.value->push_back( JsonValue(std::string("Hello world!")) );
std::cout << bob.toString();
there we go, a value-semantics Json data type in C++.
Live example.
In c++11, you can use boost::any or boost::variant. Everything I did above works with them, except the deduction guide (which is just syntactic sugar).
All of the alternative plans also work; a value pointer, surrendering copy and using unique ptr, a cow pointer, etc.
You can also roll your own any or variant, or find a stand-alone one, if you dislike boost.
template<class T, class=void>
struct has_clone_method:std::false_type{};
template<class T>
struct has_clone_method<T,
decltype( void(&T::clone) )
>:std::true_type{};
template<class T,
typename std::enable_if<!has_clone_method<T>{}, bool>::type = true
>
std::unique_ptr<T> do_clone( T const& t ) {
return std::make_unique<T>(t);
}
template<class T,
typename std::enable_if<has_clone_method<T>{}, bool>::type = true
>
std::unique_ptr<T> do_clone( T const& t ) {
return t.clone();
}
template<class T>
struct value_ptr:std::unique_ptr<T>
{
using base = std::unique_ptr<T>;
using base::base;
using base::operator=;
value_ptr()=default;
value_ptr(value_ptr&&)=default;
value_ptr& operator=(value_ptr&&)=default;
template<class D,
typename std::enable_if<std::is_base_of<T, D>::value, bool> = true
>
value_ptr( value_ptr<D> const& o ):
base( o?do_clone(*o):nullptr)
{}
template<class D,
typename std::enable_if<std::is_base_of<T, D>::value, bool> = true
>
value_ptr( value_ptr<D>&& o ):
base( std::move(o) )
{}
value_ptr( base b ):base(std::move(b)) {}
value_ptr(value_ptr const& o):
base( o?do_clone(*o):nullptr )
{}
value_ptr& operator=(value_ptr const& o) {
if (!o)
{
this->reset();
}
else if (this != &o) // test only needed for optimization
{
auto tmp = do_clone(*o);
swap( (base&)*this, tmp );
}
return *this;
}
};
template<class T, class...Args>
value_ptr<T> make_value_ptr( Args&&...args ) {
std::unique_ptr<T> retval( new T(std::forward<Args>(args)...) );
return std::move(retval);
}
class BasicJsonType {
public:
virtual std::string toString() const = 0;
virtual void setNull() = 0;
virtual bool isNull() const = 0;
virtual std::unique_ptr<BasicJsonType> clone() const = 0;
virtual ~BasicJsonType() = default;
};
using Json = value_ptr<BasicJsonType>;
using JsonVector = std::vector<Json>;
// your own to_json_string for the type in question
template<class T>
std::string to_json_string( T const& ) = delete;
std::string to_json_string( std::string const& s ) { return s; }
std::string to_json_string( double const& d )
{
std::stringstream ss;
ss << d;
return ss.str();
}
template <typename T>
class JsonValue:public BasicJsonType {
public:
JsonValue() = default;
JsonValue(JsonValue const&) = default;
JsonValue(JsonValue &&) = default;
JsonValue& operator=(JsonValue const&) = default;
JsonValue& operator=(JsonValue &&) = default;
JsonValue( T t ):value(make_value_ptr<T>(std::move(t))) {}
value_ptr<T> value;
std::string toString() const final {
if (value)
return to_json_string(*value);
else
return "(null)";
}
bool isNull() const final {
return !static_cast<bool>(value);
}
void setNull() final {
value = nullptr;
}
std::unique_ptr<BasicJsonType> clone() const final {
return std::unique_ptr<JsonValue>(new JsonValue(*this));
}
};
using JsonNumber = JsonValue<double>;
using JsonString = JsonValue<std::string>;
using JsonArray = JsonValue<JsonVector>;
std::string to_json_string( JsonVector const& arr )
{
std::stringstream ss;
ss << "{";
for (auto&& elem:arr)
{
if (elem)
{
ss << elem->toString();
}
ss << ",";
}
ss << "}";
return ss.str();
}
int main() {
JsonArray arr;
arr.value = make_value_ptr<JsonVector>();
arr.value->push_back( make_value_ptr<JsonNumber>( 3.14 ));
arr.value->push_back( make_value_ptr<JsonString>( "Hello World" ));
std::cout << arr.toString() << "\n";
}
here we make value_ptr, a smart pointer that supports copy.
It uses do_clone, which calls .clone() if it exists, and if it does not invokes their copy constructor. This permits you to make a value_ptr<T> where T is a value type, or a value_ptr<T> where T is an abstract type with a .clone() method.
I use it for a low-quality "optional" within JsonValue itself (a nullable type).
A JsonVector is then a vector of value_ptr<BasicJsonType>.
A BasicJsonType is implemented in JsonValue, where it stores it data in turn in a value_ptr<T>.
An iterative improvement would be to move the polymorphism to an internal detail.
Have a JsonValue that stores a value_ptr to a JsonBase. The JsonStorage<T> class implements JsonBase, and is not itself nullable.
JsonValue knows all 4 types that it can be. It provides interfaces that try-to-get the value of a specific type, and fail if you ask for the wrong type.
This reduces indirection, and gives the result that there isn't a NULL of type double, string, array that is distinct.
class JsonData {
public:
virtual std::string toString() const = 0;
virtual std::unique_ptr<JsonData> clone() const = 0;
virtual ~JsonData() = default;
};
using JsonPoly = value_ptr<JsonData>;
template<class T>
class JsonStorage:public JsonData {
public:
T value;
std::string toString() const final {
return to_json_string(value);
}
JsonStorage( T t ):value(std::move(t)) {}
JsonStorage() = default;
JsonStorage( JsonStorage const& )=default;
JsonStorage( JsonStorage && )=default;
JsonStorage& operator=( JsonStorage const& )=default;
JsonStorage& operator=( JsonStorage && )=default;
std::unique_ptr<JsonData> clone() const final {
return std::unique_ptr<JsonStorage>(new JsonStorage(*this));
}
};
struct JsonValue {
JsonValue() = default;
JsonValue( JsonValue const& ) = default;
JsonValue( JsonValue && ) = default;
JsonValue& operator=( JsonValue const& ) = default;
JsonValue& operator=( JsonValue && ) = default;
explicit operator bool() { return static_cast<bool>(data); }
std::string toString() const {
if (!data)
return "(null)";
else
return data->toString();
}
template<class T>
T* get() {
if (!data) return nullptr;
JsonStorage<T>* pValue = dynamic_cast<JsonStorage<T>*>(data.get());
if (!pValue) return nullptr;
return &(pValue->value);
}
template<class T>
T const* get() const {
if (!data) return nullptr;
JsonStorage<T> const* pValue = dynamic_cast<JsonStorage<T>*>(data.get());
if (!pValue) return nullptr;
return &(pValue->value);
}
JsonValue( double d ):
data( make_value_ptr<JsonStorage<double>>(d))
{}
JsonValue( std::string s ):
data( make_value_ptr<JsonStorage<std::string>>(s))
{}
JsonValue( char const* str ):
data( make_value_ptr<JsonStorage<std::string>>(str))
{}
JsonValue( std::initializer_list<JsonValue> );
private:
value_ptr<JsonData> data;
};
using JsonVector = std::vector<JsonValue>;
std::string to_json_string( JsonVector const& arr )
{
std::stringstream ss;
ss << "{";
for (auto&& elem:arr)
{
ss << elem.toString();
ss << ",";
}
ss << "}";
return ss.str();
}
JsonValue::JsonValue( std::initializer_list<JsonValue> il ):
data( make_value_ptr<JsonStorage<JsonVector>>( il ))
{}
int main() {
JsonValue arr = {JsonValue{3.14}, JsonValue{"Hello World"}};
std::cout << arr.toString() << "\n";
}
Live example.
Here, given a JsonValue v (not a template), you can ask v.get<double>() which returns a pointer-to-double if and only if the value contains a double.
JsonValue v = 3.14 works, as does JsonValue str = "hello".
Adding new types requires a to_json_string overload, and that the type supported be regular.
JsonValue is a polymorphic value type. The virtual stuff is all implementation details, not exposed to the end user. We do type erasure internally. It is basically a std::any, with an extra toString method.
I have a situation here...
I want to design a Factory where I can call a function with same name and no parameters but return different data Types. Based on the SubClassName I need to instantiate the Object.
Need help or lead on any design pattern to follow?
EDIT:
An abstract pseudo code...
class parent{
public:
virtual string getName() = 0;
//some virtual function.. not sure how to design. As the return type is dynamic.
*** getValue(){}
};
class A : public parent{
int x;
public:
virtual string getName(){ return "A";}
virtual int getValue(){retun x;}
};
class B : public parent{
string s;
public:
virtual string getName(){ return "B";}
virtual string getValue(){ return s;}
};
void main(){
string callingClass = "B";
parent * arrayPtrs[2];
arrayPtrs[0] = new A;
arrayPtrs[1] = new B;
for (loop through array, through iterator i){
if(arrayPtrs[i]->getName == callingClass ){
cout<<arrayPtrs[i]->getValue;
}
}
}
In C++ a function can only have one return type at a time, and you cannot change that dynamically.
However - as suggested by #mch - you can use template specializations. Keep in mind though, that this method is not dynamic. Your functions will be generated at compile time.
If I understood your question correctly, maybe this can be of help.
class MyObject1
{
//...
};
class MyObject2
{
//...
};
template<typename T>
struct Factory
{
constexpr static T gen();
};
template<>
struct Factory<MyObject1>
{
constexpr static MyObject1 gen()
{
return MyObject1(/*... whatever parameters you see fit ...*/);
}
};
template<>
struct Factory<MyObject2>
{
constexpr static MyObject2 gen()
{
return MyObject2(/*... whatever parameters you see fit ...*/);
}
};
int main()
{
auto myObj = Factory<MyObject1>::gen();
return 0;
}
Although this method seems fairly useless to me. You could simply call the desired constructor instead of this.
But then again, I'm not sure if this is what you thought of. If I made any mistakes please feel free, to correct me. I'll try to edit my answer best as I can.
EDIT:
To keep the virtual functionality too, the only way I can think of is type erasure: see https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Type_Erasure
The closest I could get to what you've asked for is this:
#include <iostream>
#include <string>
#include <any>
class parent {
public:
// you can use this too but I think type checking is more handy
// see in main function
/* virtual std::string getName() const = 0; */
virtual std::any getValue() const = 0;
};
class A : public parent {
public:
typedef int value_type;
private:
value_type x;
public:
A(value_type x) :
x(x)
{}
/* virtual std::string getName() const override { return "A"; } */
virtual std::any getValue() const override
{ return this->x; }
};
class B : public parent {
public:
typedef std::string value_type;
private:
value_type s;
public:
B(const value_type& s) :
s(s)
{}
/* virtual std::string getName() const override { return "B"; } */
virtual std::any getValue() const override
{ return this->s; }
};
int main(){
using callingClass = A;
parent* arrayPtrs[2];
arrayPtrs[0] = new A(42);
arrayPtrs[1] = new B("my string");
for (unsigned i = 0; i < sizeof(arrayPtrs) / sizeof(parent*); ++i)
{
// Note:
// dynamic cast will return nullptr if $callingClass
// is not a derived class
if (dynamic_cast<callingClass*>(arrayPtrs[i]))
std::cout << std::any_cast<callingClass::value_type>(arrayPtrs[i]->getValue()) << std::endl;
}
return 0;
}
I hope this one helps.
Note, that I used dynamic_cast to check the correct type. If you know a better solution, you can use that, too. But under these circumstances I couldn't think of any better.
EDIT2:
#include <iostream>
#include <string>
#include <tuple>
class some
{
using id = size_t;
template<typename T>
struct type { static void id() { } };
template<typename T>
static id type_id() { return reinterpret_cast<id>(&type<T>::id); }
template<typename T>
using decay = typename std::decay<T>::type;
template<typename T>
using none = typename std::enable_if<!std::is_same<some, T>::value>::type;
struct base
{
virtual ~base() { }
virtual bool is(id) const = 0;
virtual base *copy() const = 0;
} *p = nullptr;
template<typename T>
struct data : base, std::tuple<T>
{
using std::tuple<T>::tuple;
T &get() & { return std::get<0>(*this); }
T const &get() const& { return std::get<0>(*this); }
bool is(id i) const override { return i == type_id<T>(); }
base *copy() const override { return new data{get()}; }
};
template<typename T>
T &stat() { return static_cast<data<T>&>(*p).get(); }
template<typename T>
T const &stat() const { return static_cast<data<T> const&>(*p).get(); }
template<typename T>
T &dyn() { return dynamic_cast<data<T>&>(*p).get(); }
template<typename T>
T const &dyn() const { return dynamic_cast<data<T> const&>(*p).get(); }
public:
some() { }
~some() { delete p; }
some(some &&s) : p{s.p} { s.p = nullptr; }
some(some const &s) : p{s.p->copy()} { }
template<typename T, typename U = decay<T>, typename = none<U>>
some(T &&x) : p{new data<U>{std::forward<T>(x)}} { }
some &operator=(some s) { swap(*this, s); return *this; }
friend void swap(some &s, some &r) { std::swap(s.p, r.p); }
void clear() { delete p; p = nullptr; }
bool empty() const { return p; }
template<typename T>
bool is() const { return p ? p->is(type_id<T>()) : false; }
template<typename T> T &&_() && { return std::move(stat<T>()); }
template<typename T> T &_() & { return stat<T>(); }
template<typename T> T const &_() const& { return stat<T>(); }
template<typename T> T &&cast() && { return std::move(dyn<T>()); }
template<typename T> T &cast() & { return dyn<T>(); }
template<typename T> T const &cast() const& { return dyn<T>(); }
template<typename T> operator T &&() && { return std::move(_<T>()); }
template<typename T> operator T &() & { return _<T>(); }
template<typename T> operator T const&() const& { return _<T>(); }
};
using any = some;
class parent {
public:
// you can use this too but I think type checking is more handy
/* virtual std::string getName() const = 0; */
virtual any getValue() const = 0;
};
class A : public parent {
public:
typedef int value_type;
private:
value_type x;
public:
A(value_type x) :
x(x)
{}
/* virtual std::string getName() const override { return "A"; } */
virtual any getValue() const override
{ return this->x; }
};
class B : public parent {
public:
typedef std::string value_type;
private:
value_type s;
public:
B(const value_type& s) :
s(s)
{}
/* virtual std::string getName() const override { return "B"; } */
virtual any getValue() const override
{ return this->s; }
};
int main(){
using callingClass = A;
parent* arrayPtrs[2];
arrayPtrs[0] = new A(42);
arrayPtrs[1] = new B("my string");
for (unsigned i = 0; i < sizeof(arrayPtrs) / sizeof(parent*); ++i)
{
// Note:
// dynamic cast will return nullptr if $callingClass
// is not a derived class
if (dynamic_cast<callingClass*>(arrayPtrs[i]))
std::cout << arrayPtrs[i]->getValue()._<callingClass::value_type>() << std::endl;
}
return 0;
}
This snipped is in case you cannot use C++17 features, and is based on:
any class
I like to make function which get by reference variable from any integer (float , int , double ..) to as custom type . This type should know which type it was constructed from. For example, say I build my custom type
class Variable
{
public:
Variable(int &v)
Variable(float &v)
Variable(double &v)
Variable(short &v)
void setNuwValue(int &v)
void setNuwValue(float &v)
void setNuwValue(double &v)
void setNuwValue(short &v)
var_type_enum getType();
};
Now in my app I have function which takes this Variable type as an argument
void modifyVar(Variable& var)
{
//1.how to know the var type it can return enum of types or string what ever ..
var_type_enum type = var.getType();
var.setNuwValue(3);
}
As you you can see this is only pseudo code without the implementation which I don't know how to implement and I need help.
In short I want to be able to implement global type var as used in for example javascript "var" type
Try with this:
enum VT
{
VT_int,
VT_float,
VT_double,
VT_short
}
class Variable
{
int i;
float f;
double d;
short s;
VT type;
public:
Variable() : i(0), f(0), d(0), s(0) {}
Variable(int &v) { i = v; type = VT_int; }
Variable(float &v) { f = v; type = VT_float; }
Variable(double &v) { d = v; type = VT_double; }
Variable(short &v) { s = v; type = VT_short; }
void setNuwValue(int &v) { i = v; type = VT_int; }
void setNuwValue(float &v) { f = v; type = VT_float; }
void setNuwValue(double &v) { d = v; type = VT_double; }
void setNuwValue(short &v) { s = v; type = VT_short; }
VT getType() const { return type; }
};
Probably you can make use of templates as shown below.
template<typename T> class Variable
{
public:
const char* getType()
{
return typeid(T).name();
}
void setNuwValue( const T& ValueIn )
{
m_Value = ValueIn;
}
private:
T m_Value;
};
template<typename T>
void modifyVar(Variable<T>& var)
{
const char* type = var.getType();
var.setNuwValue(3);
}
Below example call will return "double" when getType() is called.
Variable<double>Var;
modifyVar( Var );
In C++11, I'd like to have a member variable in a class and a constructor for its initialization only if its default template value was chosen (only for supported types like int, of course).
What are recommended ways to achieve this (boost allowed)?
Something like:
template< int _x = -1 > struct C {
C() {} // only available if _x != -1
C( int x ) : x( x ) {} // only available if _x == -1
// more methods that are common for all _x and refer to _x / x
private:
int x; // only available if _x == -1
// more members that are common for all _x
};
Or, put in another way: For size and speed optimization, I would like to use a compile time constant instead of a value stored in a member variable if another value than the template default was chosen.
--
Here is an example to make everything clearer:
template< int _size = -1 > struct Block {
Block() { buf = mmap( _size, ... ); } // exists only when size!=-1
Block( int s ) { buf = mmap( size = s, ... ); } // exists only when size==-1
~Block() { munmap( buf, getSize() ); } // should use the correct size
int getSize() const { return ???; } // gets _size if !=-1, size otherwise
// other methods that use buf and getSize()
private:
void *buf;
const int size; // only exists for size == -1!
};
This solves it partially:
template< int _x > struct X {
int getX() const { return _x; }
};
template<> struct X< -1 > {
X( x ) : x( x ) {}
int getX() const { return _x; }
private:
int x;
};
template< int _x = -1 > struct C : X< _x > {
C() {} // only available if _x != -1
C( int x ) : X< _x >( x ) {} // only available if _x == -1
// more methods that are common for all _x and use this->getX()
};
But what about the constructors of C, and are other / nicer solutions available?
Just an idea, but maybe it helps: You could try to use a base class only for the minimal differences and "fake" the member variable for when it's not there to allow the rest to compile:
template< int _x > class B
{
public:
B() {}
protected:
static const int x = _x;
};
template<> class B< -1 >
{
public:
B( int i ) : x( i ) {}
protected:
int x;
};
template< int _x = -1 >
class C : public B<_x>
{
public:
using B<_x>::B; // inherit B's ctors
void f()
{
if ( x == ... ) // uses either the member variable x or the static const int x!
}
};
but as I said, it's just an idea...
Specialization is the way to go:
template <int N> struct C
{
C(int n) : n_(n) { }
int n;
};
template <> struct C<-1>
{
C() { }
C(int n) : n_(n) { }
int n;
};
I'm with Kerrek SB on this one. Put your common code, namely the runtime buffer handling in a common base class an create two derived classes, one for your statically sized buffer class and one for your dynamic buffer class. Or better yet, according to common coding guidelines, use composition.
class buffer_impl {
public:
buffer_impl(int size) : data_ {mmap( size, ... )}, size_ {size} {}
~buffer_impl() { munmap( data_, getSize() ); }
int getSize() const noexcept { return size_; }
// other buffer routines
// ...
private:
void* data_;
int size_;
};
template <int _size = -1 >
class buffer { // static size
public:
buffer() : impl_ {_size} {}
static constexpr int getSize() noexcept { return _size; }
private:
buffer_impl impl_;
};
template <>
class buffer<-1> { // dynamic size
public:
buffer(int size) : impl_ {size} {}
int getSize() const noexcept { return impl_.getSize(); }
private:
buffer_impl impl_;
};