How to create special words - c++

I'm trying to build a templat-class A and call its default constructor via a special word "NONE.
consider I have:
template<class T>
class A {
public:
A():_val(0);
A(T val):_val(val);
private:
int _val;
}
and I want to be able to write
A<int> x = None;
which will call A();
I was thinking maybe I can use some sort of typedef, but I don't know how

You could provide a dummy type and a constructor that takes that type and does the equivalent of default constructing an instance. For example,
struct None_t {};
constexpr None_t None{}; // const None_t None = {}; in C++03
template<class T>
class A {
public:
A() : _val() {};
A(None_t) : A() {} // A(None_t) : _val() {} in C++03
A(T val) : _val(val) {}
private:
T _val;
};
int main()
{
A<int> x = None;
}
Note I changed _val to from int to T, since otherwise the template doesn't make much sense.

The usual way would be to create a tag class, in this case none_type and have a constexpr (or static const) model of it available.
struct none_type {};
constexpr auto none = none_type {};
template<class T>
class A {
public:
A():_val(0) {};
A(none_type) : A() {};
A(int val):_val(val) {};
private:
int _val;
};
int main()
{
A<int> a = none;
}

Related

Factory Object for different objects types

Suppose to have the following class structure:
template <typename T, typename U>
class Base
{
public:
virtual ~Base<T, U>(){};
virtual U show() = 0;
protected:
T foo;
};
class DerivateA : public Base<int, int>
{
public:
DerivateA() { foo = 7; };
virtual int show() override { return foo; };
};
class DerivateB : public Base<std::string, std::string>
{
public:
DerivateB() { foo = "Hello"; };
virtual std::string show() override { return foo; };
};
Is there any way I can create a factory object with a Create() function that, based on an input value, returns a pointer to either DerivateA or DerivateB?
Not sure if I understood your issue correctly, but it could be smth like:
template<typename T, typename U>
class Base
{
protected:
explicit Base(T arg) : foo{std::move(arg)} {}
public:
virtual ~Base<T, U>() = default;
virtual U show() = 0;
protected:
T foo;
};
template<typename T>
class Derivate : public Base<T, T>
{
using base_type = Base<T, T>;
public:
explicit Derivate(const T& arg) : base_type(arg) { };
T show() override { return base_type::foo; };
};
class Factory
{
public:
template<typename T>
static Derivate<T>* create(const T& arg)
{ return new Derivate<T>{arg}; }
};
and we could use it like:
Base<int, int>* d1 = Factory::create(3);
Base<string, string>* d2 = Factory::create(string{"string"});

Template arguments in constructor of non-template class

I want to have a constructor of a non-template class which is templated by a type. Can anyone help here?
class A
{
public:
static int GetId(){ return 5;}
};
class B
{
public:
B(int id){ _id = id;}
template<typename T>
B() {_id = T::GetId();}
template<typename T>
static B* newB() {return new B(T::GetId());}
private:
int _id;
};
void doSome()
{
B* p1 = B::newB<A>(); //works
B* p2 = new B<A>(); //doesn't compile -- ">>B<< is no template"
}
All template parameters of a constructor template must be deducible (or have default arguments), because there is no syntax for explicitly passing template arguments to a constructor (as you've learned).
There are several possible ways around this:
Provide a constructor-like function template. You're already doing this with newB, there's just no need to force dynamic allocation:
template <class T>
B create() { return B(T::GetId()); }
Provide a tag type and parameterise the consturctor by that:
template <class T>
struct Tag {};
class B
{
public:
template <class T>
B(Tag<T>) : _id(T::GetId()) {}
};
//usage:
B b(Tag<A>());
You cannot explicitly specify the constructor template parameter. It must be deductible.
One solution is to use a helper parameter:
template <class T>
struct Type_holder { using Type = T; };
class B {
public:
B(int id) : id{id} {}
template<typename T>
B(Type_holder<T>) : id{T::GetId()} {}
private:
int id;
};
auto foo()
{
B b{Type_holder<A>{}};
}
Also, please use constructor initialization lists. And careful with those dynamic allocations. Don't use it if it's not needed. And when it's needed use smart pointers.

constexpr non-static members for classes. Are they really compile time?

Consider a class with constexpr non static member function.
template <int k> class A { A() {} };
template <> class B : public A <k> {
B() : A{} {}
constexpr int foo() const { return k+42; }
}
Is foo() really compile time with any object of B? What about constexpr members?
template <int k> class A { A() {} };
template <> class B : public A <k> {
B() : A{} {}
constexpr int foo_var = k+42;
}
Will accesses to foo_var be compile time substituted? Will B have foo_var in its object memory layout?
What about std::array<T,N>::size()??

Get size of polymorphic object

I want to be able to get the size of polymorphic object. At the moment I got this:
struct Base {
virtual std::size_t size() const {
return sizeof(*this);
}
};
struct Derived : Base {
virtual std::size_t size() const {
return sizeof(*this);
}
};
Which is literally copy & paste. I want to do better. Suppose I really hate macros and CRTP seems like the only sensible approach. Let us give it a try:
struct SizedBase {
virtual std::size_t size() const = 0;
};
template <typename Type>
struct Sized : virtual SizedBase {
std::size_t size() const override {
return sizeof(Type);
}
};
struct Base : Sized<Base> {};
struct Derived : Base, Sized<Derived> {};
This looks much better, but sadly is ill-formed: Derived contains two final overriders for size() from Base and from Sized<Derived>. We can solve this by inheriting through Sized:
struct SizedBase {
virtual std::size_t size() const = 0;
};
template <typename Type, typename... SizedBases>
struct Sized : virtual SizedBase, SizedBases... {
std::size_t size() const override {
return sizeof(Type);
}
};
struct Base : Sized<Base> {};
struct Derived : Sized<Derived, Base> {};
This works as intended, however gets somewhat confusing in the event of multiple inheritance and prohibits altering accessibility/virtualness of bases.
So, is there a better way?
Not that anyone should really use this, but...
template <typename>
struct None1 {};
template <typename>
struct None2 {};
template <typename T>
struct PrivateBase { using Tpriv = T; using Tprot = None1<T>; using Tpub = None2<T>; };
template <typename T>
struct ProtectedBase { using Tpriv = None1<T>; using Tprot = T; using Tpub = None2<T>; };
template <typename T>
struct PublicBase { using Tpriv = None1<T>; using Tprot = None2<T>; using Tpub = T; };
template <typename K>
struct TriBase : private K::Tpriv, protected K::Tprot, public K::Tpub {};
template <typename T, typename ... Bases>
struct Sized : private Bases::Tpriv..., protected Bases::Tprot..., public Bases::Tpub...
{
virtual size_t size() { return sizeof(T); }
};
struct Foo : Sized<Foo> {};
struct X{};
struct Y{};
struct Bar : Sized<Bar, PrivateBase<X>, ProtectedBase<Y>, PublicBase<Foo>> {};
int main ()
{
Bar b;
Foo* f = &b;
X* x = &b; // error : private base
Y* y = &b; // error : protected base
}
Virtual inheritance is left as an exercise to the reader.
The order of base classes is not preserved, but you should not depend on it anyway.
Something that is a little bit more production-friendly can be implemented like this (this is a rough sketch):
#include <cstdlib>
#include <typeinfo>
#include <unordered_map>
#include <memory>
#include <iostream>
struct myinfo
{
size_t size;
// any other stuff
};
using TypeInfoRef = std::reference_wrapper<const std::type_info>;
struct Hasher
{
std::size_t operator()(TypeInfoRef code) const
{
return code.get().hash_code();
}
};
struct EqualTo
{
bool operator()(TypeInfoRef lhs, TypeInfoRef rhs) const
{
return lhs.get() == rhs.get();
}
};
static std::unordered_map<TypeInfoRef, myinfo, Hasher, EqualTo> typemap;
template <typename K>
struct typemap_initializer
{
typemap_initializer()
{
typemap[typeid(K)] = myinfo{sizeof(K)};
}
};
struct Base
{
virtual ~Base() {}
size_t size() { return typemap[typeid(*this)].size; }
template<typename K, typename... Arg>
friend K* alloc(Arg...);
private:
void* operator new(size_t sz) { return ::operator new(sz); }
};
template<typename K, typename... Arg>
K* alloc(Arg... arg)
{
static typemap_initializer<K> ti;
return new K(arg...);
}
struct Foo : Base {int a;};
struct Bar : Foo {int b; int c;};
int main ()
{
Foo* f = alloc<Foo>();
Bar* g = alloc<Bar>();
std::cout << f->size() << std::endl;
std::cout << g->size() << std::endl;
}
Of course one gives up the familiar Foo* foo = new Foo syntax, but in the era of ubiquitous std::make_shared<> this is not a big problem.

How to forward std::initializer_list<T>?

I am trying to forward a std::initializer_list but
no known conversion from 'std::initializer_list<A>' to 'std::initializer_list<B>'
Here is the test code
#include <iostream>
class B {
};
class A: public B {
};
class not_working {
private:
void fun(std::initializer_list<B> p) {
}
public:
template<typename T>
not_working(std::initializer_list<T> args) {
fun(args);
}
};
class working {
private:
void fun(std::initializer_list<B> p) {
}
public:
working(std::initializer_list<B> args) {
fun(args);
}
};
int main(){
working{A{}, A{}};
//not_working{A{}, A{}};
}
How can I forward the std::initializer_list
without explicit casting not_working{(B)A{}, (B)A{}}; ?
Why is this a problem for me ?
I have a proxy-class that forwards the constructor-parameters to a class.
Something like this:
template<typename T>
class proxy {
T real;
template<typename S> proxy(std::initializer_list<S> p): real(p) {}
template<typename S...> proxy(S ... p): real(p ...) {}
};
You cant, and the reason is the same as why you also could not cast a std::vector<A> to a std::vector<B>. Containers of different types are completely unrelated.
The only way to "change" the type of a container is to construct a new container of the new type (eg, std::vector<B>(a.begin(), a.end()) -- but beware of slicing!).
Posting answer from comments of question to increase visibility of the solution:
Standard solution is to use std::forward. This fails forwarding initializer lists.
template<typename T>
class proxy {
T real;
public:
template<typename ... S> proxy(S ... p): real{std::forward<S>(args)...} {}
};
Using std::move, also works with std::initializer_list (provided by #dyp) :
template<typename T>
class proxy {
T real;
public:
template<typename ... S> proxy(S ... p): real{std::move(p) ...} {}
};