I want to make template specializations for classes with unknown name, I only know their base, and i want all derived classes to fall onto the specialized template functions.
The following code is a working one for Case 1-4. I couldn't make Case 5 to work.
Also this is mostly runtime checking with the is_base_of, a much more effective one would be a compile time solution, but i failed at that. :(
#include <typeinfo>
#include <iostream>
struct MyClass {};
struct Rnd : public MyClass {};
void* JustAVoidPointer=new int;
void* AnOtherPointer = new int;
struct A
{
template <typename T> operator T() const {
if (std::is_base_of<MyClass, T>::value == true)
{
JustAVoidPointer = (MyClass*)(new T);
std::cout << "Case 3"; return *((T*)(JustAVoidPointer));
}
std::cout << "Case 1"; return *((T*)AnOtherPointer);
}
//template <typename T> operator T&() {
// std::cout << "Case 5"; return *(this->operator T* ());
//}
template <typename T> operator T*() const {
if (std::is_base_of<MyClass, T>::value == true)
{
JustAVoidPointer = (MyClass*) new T;
std::cout << "Case 4"; return (T*)(JustAVoidPointer);
}
std::cout << "Case 2"; return *((T**)AnOtherPointer);
}
}a;
void main()
{
auto CantUseTheStructsName = [&]() {
struct Rnd : public MyClass {};
int z = a; //Case 1
int* w = a; //Case 2
Rnd x = a; //Case 3
Rnd* y = a; //Case 4
//Rnd& z=a; //Case 5
char* xx=0; std::cin >> xx;
}; CantUseTheStructsName();
}
I would appreciate any help or advice what you could give me, Thank you!:)
I have a feeling that it's impossible to differentiate between a reference operator template and a non reference one, the reference one always takes precedence if we provide both.
A workaround, and a compile time solution:
#include <typeinfo>
#include <iostream>
struct MyClass {};
struct Rnd : public MyClass {};
void* JustAVoidPointer=0;
void* AnOtherPointer = new int;
struct A
{
template <typename T, typename F = T*> operator T&() const {
return *((T*)CheckType(F{}, std::is_pointer<T>{}, std::is_base_of<MyClass, std::remove_pointer<T>::type>{}));
}
template <typename T> T* CheckType(T*, std::false_type, std::false_type) const {
std::cout << " Case 1";
return ((T*)AnOtherPointer);
}
template <typename T> T* CheckType(T*, std::true_type, std::false_type) const {
std::cout << " Case 2";
return ((T*)AnOtherPointer);
}
template <typename T> T* CheckType(T*, std::false_type, std::true_type) const {
std::cout << " Case 3";
JustAVoidPointer = (MyClass*)(new T);
return ((T*)JustAVoidPointer);
}
template <typename T> T* CheckType(T*, std::true_type, std::true_type) const {
std::cout << " Case 4";
JustAVoidPointer = (MyClass*)(new std::remove_pointer<T>::type);
return ((T*)(&JustAVoidPointer));
}
}a;
void main()
{
auto CantUseTheStructsName = [&]() {
struct Rnd : public MyClass {};
int x = a; //Case 1
int& y = a; //Case 1
int* z = a; //Case 2
Rnd j = a; //Case 3
Rnd& k = a; //Case 3
Rnd* f = a; //Case 4
char* xx=0; std::cin >> xx;
}; CantUseTheStructsName();
}
Related
I have a template class where I try to convert a template verision to another via operator overload
enum MyTypes {A,B,C}
template<MyTypes T>
MyClass {
const static MyType type_ = T;
template<MyTypes U>
MyClass<U> convert(MyTypes t) {
MyType<U> ret = MyType<U>();
....
return r;
}
template<MyTypes U>
MyClass<U> operator()() {
return convert(U);
}
}
However, this yields (on gcc, c11)
conversion from MyClass<0u> to non-scalar type MyClass<1u> requested
removing the template functions and trying
MyClass<A> operator()() {
MyClass<A> a = MyClass<A>();
...
return a;
}
throws
the error operator cannot be overloaded
Basically, what I am trying to achieve is that if I have
MyClass<A> a = MyClass<A>;
MyClass<B> b = a;
that it creates a new MyClass based on a and the conversion. Any idea what my mistake here is?
EDIT:
I tossed out one template function, just leaving the operator
template<MyTypes U>
MyClass<U> operator()() {
MyClass<U> ret = MyClass<U>();
...
return ret;
}
but this still yields
conversion from MyClass<0u> to non-scalar type MyClass<1u> requested
when trying to do
MyClass<B> = a
The following converts the value and allows for the assignment:
#include <iostream>
#include <string>
enum MyTypes { A, B, C };
template<MyTypes T>
struct MyClass{
const static MyTypes type_ = T;
std::string history{"started as " + std::to_string(T)};
template<MyTypes U>
operator MyClass<U> () {
return {history+" then became " + std::to_string(U)};
}
};
int main()
{
MyClass<A> a;
MyClass<B> b = a;
MyClass<C> c = b;
std::cout << a.history << '\n';
std::cout << b.history << '\n';
std::cout << c.history << '\n';
}
Output:
started as 0
started as 0 then became 1
started as 0 then became 1 then became 2
My real example is quite big, so I will use a simplified one. Suppose I have a data-type for a rectangle:
struct Rectangle {
int width;
int height;
int computeArea() {
return width * height;
}
}
And another type that consumes that type, for example:
struct TwoRectangles {
Rectangle a;
Rectangle b;
int computeArea() {
// Ignore case where they overlap for the sake of argument!
return a.computeArea() + b.computeArea();
}
};
Now, I don't want to put ownership constraints on users of TwoRectangles, so I would like to make it a template:
template<typename T>
struct TwoRectangles {
T a;
T b;
int computeArea() {
// Ignore case where they overlap for the sake of argument!
return a.computeArea() + b.computeArea();
}
};
Usages:
TwoRectangles<Rectangle> x;
TwoRectangles<Rectangle*> y;
TwoRectangles<std::shared_ptr<Rectangle>> z;
// etc...
The problem is that if the caller wants to use pointers, the body of the function should be different:
template<typename T>
struct TwoRectangles {
T a;
T b;
int computeArea() {
assert(a && b);
return a->computeArea() + b->computeArea();
}
};
What is the best way of unifying my templated function so that the maxiumum amount of code is reused for pointers, values and smart pointers?
One way of doing this, encapsulating everything within TwoRectangles, would be something like:
template<typename T>
struct TwoRectangles {
T a;
T b;
int computeArea() {
return areaOf(a) + areaOf(b);
}
private:
template <class U>
auto areaOf(U& v) -> decltype(v->computeArea()) {
return v->computeArea();
}
template <class U>
auto areaOf(U& v) -> decltype(v.computeArea()) {
return v.computeArea();
}
};
It's unlikely you'll have a type for which both of those expressions are valid. But you can always add additional disambiguation with a second argument to areaOf().
Another way, would be to take advantage of the fact that there already is a way in the standard library of invoking a function on whatever: std::invoke(). You just need to know the underlying type:
template <class T, class = void>
struct element_type {
using type = T;
};
template <class T>
struct element_type<T, void_t<typename std::pointer_traits<T>::element_type>> {
using type = typename std::pointer_traits<T>::element_type;
};
template <class T>
using element_type_t = typename element_type<T>::type;
and
template<typename T>
struct TwoRectangles {
T a;
T b;
int computeArea() {
using U = element_type_t<T>;
return std::invoke(&U::computeArea, a) +
std::invoke(&U::computeArea, b);
}
};
I actually had a similar problem some time ago, eventually i opted not to do it for now (because it's a big change), but it spawned a solution that seems to be correct.
I thought about making a helper function to access underlying value if there is any indirection. In code it would look like this, also with an example similar to yours.
#include <iostream>
#include <string>
#include <memory>
namespace detail
{
//for some reason the call for int* is ambiguous in newer standard (C++14?) when the function takes no parameters. That's a dirty workaround but it works...
template <class T, class SFINAE = decltype(*std::declval<T>())>
constexpr bool is_indirection(bool)
{
return true;
}
template <class T>
constexpr bool is_indirection(...)
{
return false;
}
}
template <class T>
constexpr bool is_indirection()
{
return detail::is_indirection<T>(true);
}
template <class T, bool ind = is_indirection<T>()>
struct underlying_type
{
using type = T;
};
template <class T>
struct underlying_type<T, true>
{
using type = typename std::remove_reference<decltype(*(std::declval<T>()))>::type;
};
template <class T>
typename std::enable_if<is_indirection<T>(), typename std::add_lvalue_reference<typename underlying_type<T>::type>::type>::type underlying_value(T&& val)
{
return *std::forward<T>(val);
}
template <class T>
typename std::enable_if<!is_indirection<T>(), T&>::type underlying_value(T& val)
{
return val;
}
template <class T>
typename std::enable_if<!is_indirection<T>(), const T&>::type underlying_value(const T& val)
{
return val;
}
template <class T>
class Storage
{
public:
T val;
void print()
{
std::cout << underlying_value(val) << '\n';
}
};
template <class T>
class StringStorage
{
public:
T str;
void printSize()
{
std::cout << underlying_value(str).size() << '\n';
}
};
int main()
{
int* a = new int(213);
std::string str = "some string";
std::shared_ptr<std::string> strPtr = std::make_shared<std::string>(str);
Storage<int> sVal{ 1 };
Storage<int*> sPtr{ a };
Storage<std::string> sStrVal{ str };
Storage<std::shared_ptr<std::string>> sStrPtr{ strPtr };
StringStorage<std::string> ssStrVal{ str };
StringStorage<const std::shared_ptr<std::string>> ssStrPtr{ strPtr };
sVal.print();
sPtr.print();
sStrVal.print();
sStrPtr.print();
ssStrVal.printSize();
ssStrPtr.printSize();
std::cout << is_indirection<int*>() << '\n';
std::cout << is_indirection<int>() << '\n';
std::cout << is_indirection<std::shared_ptr<int>>() << '\n';
std::cout << is_indirection<std::string>() << '\n';
std::cout << is_indirection<std::unique_ptr<std::string>>() << '\n';
}
The X:
A common pattern I'm seeing is that the underlying code for a function is templates, but for "reasons" the template code is not available at the upper layer (pick from aversion to templates in interface, the need for a shared library and not to expose implementation to customer, reading type settings at run time instead of compile time, etc.).
This often makes the following:
struct foo { virtual void foo() = 0;}
template <typename T> struct bar : public foo
{
bar( /* Could be lots here */);
virtual void foo() { /* Something complicated, but type specific */}
};
And then an initialize call:
foo* make_foo(int typed_param, /* More parameters */)
{
switch(typed_param)
{
case 1: return new bar<int>(/* More parameters */);
case 2: return new bar<float>(/* More parameters */);
case 3: return new bar<double>(/* More parameters */);
case 4: return new bar<uint8_t>(/* More parameters */);
default: return NULL;
}
}
This is annoying, repetitive, and error prone code.
So I says to myself, self says I, there has GOT to be a better way.
The Y:
I made this. Do you all have a better way?
////////////////////////////////////
//////Code to reuse all over the place
///
template <typename T, T VAL>
struct value_container
{
static constexpr T value() {return VAL;}
};
template <typename J, J VAL, typename... Ts>
struct type_value_pair
{
static constexpr J value() {return VAL;}
template <class FOO>
static auto do_things(const FOO& foo)->decltype(foo.template do_things<Ts...>()) const
{
foo.template do_things<Ts...>();
}
};
template <typename T>
struct error_select
{
T operator()() const { throw std::out_of_range("no match");}
};
template <typename T>
struct default_select
{
T operator()() const { return T();}
};
template <typename S, typename... selectors>
struct type_selector
{
template <typename K, class FOO, typename NOMATCH, typename J=decltype(S::do_things(FOO()))>
static constexpr J select(const K& val, const FOO& foo=FOO(), const NOMATCH& op=NOMATCH())
{
return S::value()==val ? S::do_things(foo) : type_selector<selectors...>::template select<K, FOO, NOMATCH, J>(val, foo, op);
}
};
template <typename S>
struct type_selector<S>
{
template <typename K, class FOO, typename NOMATCH, typename J>
static constexpr J select(const K& val, const FOO& foo=FOO(), const NOMATCH& op=NOMATCH())
{
return S::value()==val ? S::do_things(foo) : op();
}
};
////////////////////////////////////
////// Specific implementation code
class base{public: virtual void foo() = 0;};
template <typename x>
struct derived : public base
{
virtual void foo() {std::cout << "Ima " << typeid(x).name() << std::endl;}
};
struct my_op
{
template<typename T>
base* do_things() const
{
base* ret = new derived<T>();
ret->foo();
return ret;
}
};
int main(int argc, char** argv)
{
while (true)
{
std::cout << "Press a,b, or c" << std::endl;
char key;
std::cin >> key;
base* value = type_selector<
type_value_pair<char, 'a', int>,
type_value_pair<char, 'b', long int>,
type_value_pair<char, 'c', double> >::select(key, my_op(), default_select<base*>());
std::cout << (void*)value << std::endl;
}
/* I am putting this in here for reference. It does the same
thing, but the old way: */
/*
switch(key)
{
case 'a':
{
base* ret = new derived<int>();
ret->foo();
value = ret;
break;
}
case 'b':
{
base* ret = new derived<char>();
ret->foo();
value = ret;
break;
}
case 'c':
{
base* ret = new derived<double>();
ret->foo();
value = ret;
break;
}
default:
return NULL;
}
*/
}
Problems I see with my implementation:
It is clear and readable as mud
Template parameters MUST be types, have to wrap values in types (template <typename T, T VAL> struct value_container { static constexpr T value() {return VAL;} };)
Currently no checking/forcing that the selectors are all type-value pairs.
And the only pros:
Removes code duplication.
If the case statement gets high/the contents of do_things gets high, then we can be a little shorter.
Has anyone do something similar or have a better way?
You can always walk a type list indexed by type_param, as in:
struct foo
{
virtual ~foo() = default;
/* ... */
};
template<typename T>
struct bar : foo
{ /* ... */ };
template<typename TL>
struct foo_maker;
template<template<typename...> class TL, typename T, typename... Ts>
struct foo_maker<TL<T, Ts...>>
{
template<typename... Us>
std::unique_ptr<foo> operator()(int i, Us&&... us) const
{
return i == 1 ?
std::unique_ptr<foo>(new bar<T>(std::forward<Us>(us)...)) :
foo_maker<TL<Ts...>>()(i - 1, std::forward<Us>(us)...); }
};
template<template<typename...> class TL>
struct foo_maker<TL<>>
{
template<typename... Us>
std::unique_ptr<foo> operator()(int, Us&&...) const
{ return nullptr; }
};
template<typename...>
struct types;
template<typename... Us>
std::unique_ptr<foo> make_foo(int typed_param, Us&& us...)
{ return foo_maker<types<int, float, double, uint8_t>>()(typed_param, std::forward<Us>(us)...); };
Note: this factory function is O(n) (although a clever compiler could make it O(1)), while the switch statement version is O(1).
Just to expand YoungJohn's comment, it looks like this (I've included a single initialization of the operator, and it could be made simpler if there was no parameters, but if there are no parameters there is little reason to do this anyway :-P).
#include <functional>
#include <map>
////////////////////////////////////
//////specific impmenetation code
class base{public: virtual void foo() = 0;};
template <typename x>
struct derived : public base
{
virtual void foo() {std::cout << "Ima " << typeid(x).name() << std::endl;}
};
struct my_op
{
int some_param_; /// <shared parameter
my_op(int some_param) : some_param_(some_param){} /// <constructor
template<typename T>
base* do_stuff() const
{
std::cout << "Use some parameter: " << some_param_ << std::endl;
base* ret = new derived<T>();
ret->foo();
return ret;
}
};
base* init_from_params(int some_param, char key)
{
my_op op(some_param);
using factoryFunction = std::function<base*()>;
std::map<char, factoryFunction> mp
{
{ 'a', std::bind(&my_op::do_stuff<int>, &op)},
{ 'b', std::bind(&my_op::do_stuff<long int>, &op)},
{ 'c', std::bind(&my_op::do_stuff<double>, &op)}
} ;
factoryFunction& f = mp[key];
if (f)
{
return f();
}
return NULL;
}
int main(int argc, char** argv)
{
volatile int parameters = 10;
while (true)
{
std::cout << "Press a, b, or c" << std::endl;
char key;
std::cin >> key;
base* value = init_from_params(parameters, key);
std::cout << (void*)value << std::endl;
}
}
Pros: so much shorter, so much more standard, so much less weird template stuff. It also doesn't require the templated arguments to all be types, we can select whatever we want to initialize the function.
Cons: In theory, it could have more overhead. In practice, I totally doubt that the overhead would ever matter.
I like it!
template<class T>
foo* make_foo(int typed_param,/*more params*/)
{
return new bar<T>(/*more params*/);
}
Say if I had a vector<string> already defined and filled called test and an int called a. If I wanted to combine these 2 into a single object called combined where i could do combined[0] = test; to initialize/retrieve the object with the vector and combined[1] = a; to initialize/retrieve the object with the int, what would be the best function to do so and how would I do so? I had attempted to do vector<vector<string>, int> but this gave me an error.
Note: I am compiling with -std=c++11 if this matters.
Use a std::tuple<std::vector<std::string>,int>.
#include <tuple>
#include <vector>
#include <string>
int main() {
std::vector<std::string> test;
int a{};
std::tuple<std::vector<std::string>,int> combined;
//To access elements, use `std::get`:
std::get<0>(combined) = test;
std::get<1>(combined) = a;
}
to answer cellsheet's comment: that function already exists, it's called std::make_tuple() (see also comment by fjardon on how to store this).
Btw, why do you need to extend std::vector<std::string> by an int?
If I understand correctly what you're asking, I think you can do this with a std::pair:
std::pair<std::vector<std::string>, int> combined;
combined.first = test; // assign vector
combined.second = a; // assign int
or simply
auto combined = std::make_pair(test,a);
It requires (ugly) type elision:
#include <iostream>
#include <stdexcept>
#include <type_traits>
#include <vector>
class X {
public:
typedef std::vector<std::string> vector_type;
typedef int integer_type;
private:
enum Type {
TypeVector,
TypeInteger
};
template <bool Constant>
class Proxy
{
private:
typedef typename std::conditional<
Constant, const void, void>::type void_t;
public:
typedef typename std::conditional<
Constant, const vector_type, vector_type>::type vector_t;
typedef typename std::conditional<
Constant, const integer_type, integer_type>::type integer_t;
Proxy(vector_t& v)
: m_type(TypeVector), m_data(&v)
{}
Proxy(integer_t& i)
: m_type(TypeInteger), m_data(&i)
{}
operator vector_t& () const {
if(m_type != TypeVector) throw std::runtime_error("Invalid Type");
return *static_cast<vector_t*>(m_data);
}
operator integer_t& () const {
if(m_type != TypeInteger) throw std::runtime_error("Invalid Type");
return *static_cast<integer_t*>(m_data);
}
private:
template <typename T, typename U, bool> struct Assignment
{
static void apply(void_t*, const U&) {}
};
template <typename T, typename U>
struct Assignment<T, U, true>
{
static void apply(void_t* p, const U& value) {
*static_cast<T*>(p) = value;
}
};
template <typename T, typename U>
// Attention: Use a reference - std::is_assignable<int, int>::value> is false;
struct Assign : Assignment<T, U, std::is_assignable<T&, U>::value>
{};
public:
template <typename U>
Proxy&
operator = (const U& value) {
static_assert( ! Constant, "Assignment to Constant");
switch(m_type) {
case TypeVector:
Assign<vector_t, U>::apply(m_data, value);
break;
case TypeInteger:
Assign<integer_t, U>::apply(m_data, value);
break;
default: throw std::out_of_range("Invalid Type");
}
return *this;
}
private:
Type m_type;
void_t* m_data;
};
public:
X() : m_v{"Hello"}, m_i(1) {}
Proxy<true> operator [] (std::size_t i) const {
switch(i) {
case 0: return Proxy<true>(m_v);
case 1: return Proxy<true>(m_i);
default: throw std::out_of_range("Invalid Index");
}
}
Proxy<false> operator [] (std::size_t i) {
switch(i) {
case 0: return Proxy<false>(m_v);
case 1: return Proxy<false>(m_i);
default: throw std::out_of_range("Invalid Index");
}
}
private:
vector_type m_v;
integer_type m_i;
};
int main() {
// Note: The Proxy has no operator []
// const
{
const X x;
const X::vector_type& v = x[0];
std::cout << v[0] << " " << x[1] << std::endl;
}
// non const
{
X x;
X::vector_type& v = x[0];
v[0] = "World";
x[1] = 2;
std::cout << v[0] << " " << x[1] << std::endl;
}
}
You might consider boost::any, instead.
Can I overload a template class function in a class that extends its specialization?
I have the following piece of code (I've tried to simplify it to the bare minimum):
#include <iostream>
using namespace std;
class X {
public:
unsigned test_x() {
return 1;
}
};
class Y {
public:
unsigned test_y() {
return 2;
}
};
template <typename T, typename U>
class A {
public:
unsigned foo(U i) {
cout << "A" << endl;
return i.test_x();
}
unsigned bar(T i) {
return foo(i);
}
};
class B : public A<Y, X> {
public:
unsigned foo(Y i) {
cout << "B" << endl;
return i.test_y();
}
};
int main() {
B b = B();
Y y = Y();
cout << "Hello: " << b.bar(y) << endl;
return 0;
}
However the compiler produces the following error:
hello.cc: In member function ‘unsigned int A<T, U>::bar(T) [with T = Y, U = X]’:
hello.cc:47: instantiated from here
hello.cc:30: error: no matching function for call to ‘A<Y, X>::foo(Y&)’
hello.cc:24: note: candidates are: unsigned int A<T, U>::foo(U) [with T = Y, U = X]
Basically I would like to overload the function A::foo() in its derived class B.
Apparently what you're asking is called "static polymorphism" and it's achieved by the means of "curiously recurring template pattern":
template <typename Derived, typename T, typename U>
class A {
public:
unsigned foo(U i) {
cout << "A" << endl;
return i.test_x();
}
unsigned bar(T i) {
return static_cast<Derived*>(this)->foo(i);
}
};
class B : public A<B, Y, X> {
public:
// Uncomment this line if you really want to overload foo
// instead of overriding. It's optional in this specific case.
//using A::foo;
unsigned foo(Y i) {
cout << "B" << endl;
return i.test_y();
}
};
I don't think the overloads in derived classes cannot be used from the base class where they are to be called from.
What you can do, is to extract the foo method, so you can specialize it for B.
#include <iostream>
using namespace std;
class X {
public:
unsigned test_x() {
return 1;
}
};
class Y {
public:
unsigned test_y() {
return 2;
}
};
template <typename T, typename U>
struct Foo
{
unsigned foo(U i) {
cout << "A" << endl;
return i.test_x();
}
};
template <typename T, typename U>
class A : public Foo<T, U> {
public:
unsigned bar(T i) {
return this->foo(i);
}
};
template <>
struct Foo<Y, X>
{
public:
unsigned foo(Y i) {
cout << "B" << endl;
return i.test_y();
}
};
class B : public A<Y, X> {
};
int main() {
B b = B();
Y y = Y();
cout << "Hello: " << b.bar(y) << endl;
return 0;
}
Edit: My first answer was incorrect.
When you instantiate A with classes Y and X the call of foo(T) generates an error because there no proper overloaded method defined in A. It suffices to declare a pure virtual method of foo(T) in A and implement this method in B.
template <typename T, typename U>
class A {
public:
virtual unsigned foo(T i) = 0;
unsigned foo(U i) { /* as above */ }
unsigned bar(T i) {
return foo(i); // calls abstract foo(T)
}
};
/* B is left untouched */
Compiling this generates this output:
B
Hello: 2