template deduction/substitution fails on smart pointers - c++

Let's consider this code:
template<typename T>
struct A
{
//...
};
struct B : public A<int>
{
//...
};
template<typename T>
bool validate(A<T>* p)
{
//...
return true;
};
int main()
{
A<int>* pA;
std::cout << validate(pA) << std::endl;
B* pB;
std::cout << validate(pB) << std::endl;
}
It compiles correctly and works as expected. Now, let's say I'd need to refactor the code to use smart pointers instead, then also validate could be changed like this:
template<typename T>
bool validate(std::shared_ptr<A<T>> p)
{
//...
return true;
};
int main()
{
std::shared_ptr<A<int>> pA = std::make_shared<A<int>>();
validate(pA); //it compiles correctly
std::shared_ptr<B> pB = std::make_shared<B>();
validate(pB); //it FAILS to compile
}
You can verify that here.
What is the reason behind this?
What is the best way to solve this problem without modifying A or B?

This is because it requires to perform custom casting from shared_ptr<B> to shared_ptr<A<int>> to disambiguate the template function parameters. Disambiguation of template functions parameters doesn't even attempt to do type casting (aside from some basic stuff).
It is simply not practictical to even try. Well, theoretically there could've been a partial solution that specify which custom castings to try but there isn't. Just use SFINEA and disambiguate it yourself instead of asking compiler to do it for you.

In general you should avoid smart pointers if the called function does not change ownership! Use your raw pointer function.
You force a Generic type of A in function validate. Inheritance is not considered here.
If you ignore inheritance it could look like:
template<typename T>
bool validate(std::shared_ptr<T> p)
{
return true;
}
See on Godbolt
To force a base class I would introduce a Typetag.

The ways around this I can see possible are:
Alternative 1)
std::shared_ptr<B> pB = std::make_shared<B>();
//... do your type B related operations through pB
validate(std::shared_ptr<A<int>>(pB));
Alternative 2)
template<typename T>
bool validate(A<T> const & a)
{
//...
return true;
}
int main()
{
std::shared_ptr<A<int>> pA = std::make_shared<A<int>>();
validate(*pA);
std::shared_ptr<B> pB = std::make_shared<B>();
validate(*pB);
}
Alternative 3)
template<typename T>
bool validate(std::shared_ptr<A<T>> p)
{
//...
return true;
}
template<typename T>
bool validate(std::shared_ptr<T> p)
{
//...
return true;
}
int main()
{
std::shared_ptr<A<int>> pA = std::make_shared<A<int>>();
validate(pA); // it uses bool validate(std::shared_ptr<A<T>> p)
std::shared_ptr<B> pB = std::make_shared<B>();
validate(pB); // it uses bool validate(std::shared_ptr<T> p)
}
but that implies that the function might extend to many other types, and it is not necessarily a desired behaviour (maybe?).
Any other suggestions guys?
It would be cool if someone knows why the code in the question doesn't work in the first place.

Related

Selecting between conversion operators when they are ambiguous

I have two types:
struct A { };
struct B { };
And I have functions taking A or B:
void fnA(A); // there are a lot of these functions
void fnB(B);
And I have a type, which is convertible to A and B:
struct Foo {
operator A();
operator B();
};
So I can call fnA and fnB:
fnA(Foo()); // fine
fnB(Foo());
Now, I have overloaded function:
void fn(A);
void fn(B);
I cannot call them with Foo, because it is ambiguous:
fn(Foo()); // ambiguous, which fn is called
I'd like to fn(A) be called in this case.
I could add a third fn overload:
inline void fn(Foo foo) {
fn(A(foo));
}
But I don't like this way, as I have a lot of fn functions, and I don't want to increase the number of functions considerably (I have fn-like functions scattered all over the place, this change would increase interface size, which is bad for me, as my interface is already huge).
Another solution (which I'll choose if no better alternatives given) is to use inheritance for Foo:
struct Foo: A {
operator B();
};
In this case, compiler will choose to call fn(A) for fn(Foo()), it is not ambiguous anymore. But I'm not satisfied with this solution, as Foo is not really an A, it is a misuse of inheritance (on the other hand, it is a better solution as the previous one, as it solves the problem locally, I don't have to add a lot of unwanted fn functions).
Is there any other way to solve this problem?
Note: I'd like to have a solution, which doesn't involve explicit conversion, I'd like able to write fnA(Foo()), fnB(Foo()), and fn(Foo()).
How about a fancy template wrapper:
void fn_impl(A);
void fn_impl(B);
template<typename x_AB = A, typename x_Foo = Foo>
void fn(x_Foo && foo)
{
return fn_impl(static_cast<x_AB>(foo));
}
fn(Foo()); // calls fn_impl(A);
fn<B>(Foo()); // calls fn_impl(B);
online compiler
I think you can achieve the desired behavior by making each fn(B) overload a template:
void fn(A);
template<class = void>
void fn(B);
void bar()
{
fn(Foo());
fn(A());
fn(B());
}
This causes overload resolution to pick fn(A) before considering the templated function. The necessary work amounts to putting template<class = void> before every B overload of every function (and, if the declaration is separated from the definition, turning all such functions into template specializations).
Demo.
Just cast Foo to the appropriate type:
#include <iostream>
#include <string>
struct A { };
struct B { };
struct Foo {
operator A() { return A{}; };
operator B() { return B{}; };
};
void fn(A) { std::cout << "A"; }
void fn(B) { std::cout << "B"; }
int main()
{
fn(static_cast<A>(Foo()));
}

automatic calling custom converter of raw pointers A* <-> B*

Is it possible to define a custom converter (converter1<T> and converter2) between different types of raw pointer A* and B*,
then make all functions (fa() and fb()) in a certain class
use an appropriate converter (converter1<T> or converter2)?
In short, I want the program to convert A* to B* and vice versa USING my custom functions.
I wish it would do that automatically for my convenience.
class Manager{
void fb(B* b){ /** something complex */ }
void fa(A* a){ /** different thing complex */ }
void testCase(){
A* a= ... ;
fa(a);
fb(a); //automatic convert to B* using "converter2" (wish)
B* b= ... ;
fa(b); //automatic convert to A* using "converter1" (wish)
fb(b);
}
template<class T> T* converter1(B* b){ //hardcoded, non-static.
return this->getId<T>(b);
//^^^ just an example to show how custom it is,
// currently T=A
}
B* converter2(A* a){ //hardcoded
return a->getB();
//^^^ just an example to show how custom it is.
}
}
The real case has many A - A1, A2, A3 and so on.
A and B are not derived from each other.
I wish there is a way. I think about constructor of pointer.
No this is not possible.
Pointers are built-in types and only built-in conversions between built-in types exist. User-defined conversions only work for user-defined class types.
You may want to switch to your own brand of smart pointers to handle this.
through references (or smart pointers) it's more possible:
struct A {};
struct B {};
A& convert_to_a(A& a) { return a; }
A convert_to_a(B const& b) {
// makes a new A from a B
return A();
}
B& convert_to_b(B& b) { return b; }
B convert_to_b(A const& a) { return B(); }
struct Manager
{
template<class T>
void fa(T&& t) {
auto&& a = convert_to_a(t);
// do something with a
(void)a;
}
template<class T>
void fb(T&& t) {
auto&& b = convert_to_b(t);
// do something with b
(void)b;
}
};
int main()
{
A a;
B b;
Manager m;
m.fa(a);
m.fb(a);
m.fa(b);
m.fb(b);
}
It is not possible the way you want it.
Anyway, you can use a catch-all function and a bunch of traits to simulate it.
It follows a minimal, working example:
#include<iostream>
struct A {};
struct B {};
template<typename T>
A* ToAConverter(T*) = delete;
template<>
A* ToAConverter<B>(B *b) {
// just an example
return new A;
}
struct Manager{
void fa(A* a){ std::cout << "fa" << std::endl; }
template<typename T>
void fa(T *t) {
std::cout << "convert and forward" << std::endl;
fa(ToAConverter<T>(t));
}
void testCase(){
A *a = new A;
fa(a);
B *b = new B;
fa(b);
}
};
int main() {
Manager m;
m.testCase();
}
In case you haven't defined a converter for a specific type, you'll receive a compile-time error.
As you can see, you have no longer to call explicitly the converter when you invoke fa.

Implicitly cast wrapper class to supperclass in templated call

In designing a DSL (which compiles into C++), I found it convenient to define a wrapper class that, uppon destruction, would call a .free() method on the contained class:
template<class T>
class freeOnDestroy : public T {
using T::T;
public:
operator T&() const { return *this; }
~freeOnDestroy() { T::free(); }
};
The wrapper is designed to be completely transparent: All methods, overloads and constructors are inherited from T (at least to my knowledge), but when included in the wrapper, the free() method is called uppon destruction. Note that I explicitly avoid using T's destructor for this since T::free() and ~T() may have different semantics!
All this works fine, untill a wrapped class gets used as a member to a non-reference templated call, at which point freeOnDestroy is instantiated, calling free on the wrapped object. What I would like to happen is for the tempated method to use T instead of freeOnDestroy<T>, and to implicitly cast the parameter into the supperclass. The following code sample illustrates this problem:
// First class that has a free (and will be used in foo)
class C{
int * arr;
public:
C(int size){
arr = new int[size];
for (int i = 0; i < size; i++) arr[i] = i;
}
int operator[] (int idx) { return arr[idx]; }
void free(){ cout << "free called!\n"; delete []arr; }
};
// Second class that has a free (and is also used in foo)
class V{
int cval;
public:
V(int cval) : cval(cval) {}
int operator[] (int idx) { return cval; }
void free(){}
};
// Foo: in this case, accepts anything with operator[int]
// Foo cannot be assumed to be written as T &in!
// Foo in actuality may have many differently-templated parameters, not just one
template<typename T>
void foo(T in){
for(int i = 0; i < 5; i++) cout << in[i] << ' ';
cout << '\n';
}
int main(void){
C c(15);
V v(1);
freeOnDestroy<C> f_c(15);
foo(c); // OK!
foo(v); // OK!
foo<C>(f_c); // OK, but the base (C) of f_c may not be explicitly known at the call site, for example, if f_c is itself received as a template
foo(f_c); // BAD: Creates a new freeOnDestroy<C> by implicit copy constructor, and uppon completion calls C::free, deleting arr! Would prefer it call foo<C>
foo(f_c); // OH NO! Tries to print arr, but it has been deleted by previous call! Segmentation fault :(
return 0;
}
A few non solutions I should mention are:
Making freeOnDestroy::freeOnDestroy(const freeOnDestroy &src) explicit and private, but this seems to override T's constructor. I'd hoped it would try to implicitly convert it to T and use that as the template argument.
Assume foo receives a reference of its templated arguments (as in void foo(T &in): This is neither the case, nor desirable in some cases
Always explicitly template the call to foo, as in foo<C>(f_c): f_c itself may be templated, so it's hard to know to instantiate foo with C (yes, this could be done with creating multiple versions of foo, to remove the wrappers one by one, but I can't find a way of doing that without creating a different overload for each templated argument of foo).
In summary, my question is: Is there a clean(ish) method to ensure a base class will be casted to its superclass when resolving a template? Or, if not, is there some way of using SFINAE, by causing a substitution failure when the template argument is an instance of the wrapper class, and thus force it to use the implicit cast to the wrapped class (without duplicating each foo-like method signature possibly dozens of times)?
I presently have a work-arround that involves changes in the DSL, but I'm not entirely happy with it, and was curious if it was at all possible to design a wrapper class that works as described.
The problem here not when "wrapped class gets used as a member to a non-reference templated call".
The problem here is that the template wrapper -- and likely its superclass too -- has violated the Rule Of Three.
Passing an instance of the class as a non-reference parameter is just another way of saying "passing by value". Passing by value makes a copy of the instance of the class. Neither your template class -- nor its wrapped class, most likely -- has an explicit copy constructor; as such the copied instance of the class has no knowledge that it is a copy, hence the destructor does what it thinks it should do.
The correct solution here is not to hack something up that makes passing an instance of freeOnDestroy<T> by value end up copying T, rather than freeOnDestroy<T>. The correct solution is to add a proper copy-constructor and the assignment operator to both the freeOnDestroy template, and possibly any superclass that uses it, so that everything complies with the Rule Of Three.
You can use a properly defined detector and a sfinaed function, as it follows:
#include<iostream>
#include<type_traits>
template<class T>
class freeOnDestroy : public T {
using T::T;
public:
operator T&() const { return *this; }
~freeOnDestroy() { T::free(); }
};
template<typename T>
struct FreeOnDestroyDetector: std::false_type { };
template<typename T>
struct FreeOnDestroyDetector<freeOnDestroy<T>>: std::true_type { };
class C{
int * arr;
public:
C(int size){
arr = new int[size];
for (int i = 0; i < size; i++) arr[i] = i;
}
int operator[] (int idx) { return arr[idx]; }
void free(){ std::cout << "free called!\n"; delete []arr; }
};
class V{
int cval;
public:
V(int cval) : cval(cval) {}
int operator[] (int idx) { return cval; }
void free(){}
};
template<typename..., typename T>
std::enable_if_t<not FreeOnDestroyDetector<std::decay_t<T>>::value>
foo(T in) {
std::cout << "here you have not a freeOnDestroy based class" << std::endl;
}
template<typename..., typename T>
std::enable_if_t<FreeOnDestroyDetector<std::decay_t<T>>::value>
foo(T &in) {
std::cout << "here you have a freeOnDestroy based class" << std::endl;
}
int main(void){
C c(15);
V v(1);
freeOnDestroy<C> f_c(15);
foo(c);
foo(v);
foo<C>(f_c);
foo(f_c);
foo(f_c);
return 0;
}
As you can see by running the example, free is called only once, that is for the freeOnDestroy created in the main function.
If you want to forbid definitely freeOnDestroy as a parameter, you can use a single function as the following one:
template<typename..., typename T>
void foo(T &in) {
static_assert(not FreeOnDestroyDetector<std::decay_t<T>>::value, "!");
std::cout << "here you have a freeOnDestroy based class" << std::endl;
}
Note that I added a variadic parameter as a guard, so that one can no longer use foo<C>(f_c); to force a type to be used.
Remove it if you want to allow such an expression. It was not clear from the question.
One solution, which, although a little ugly, seems to work, is to use an overloaded unwrapping method, such as:
template<typename T> T freeOnDestroyUnwrapper(const T &in){ return in; }
template<typename T> T freeOnDestroyUnwrapper(const freeOnDestroy<T> &in){ return in; }
template<typename T> T freeOnDestroyUnwrapper(const freeOnDestroy<typename std::decay<T>::type> &in){ return in; }
template<typename T> T& freeOnDestroyUnwrapper(T &in){ return in; }
template<typename T> T& freeOnDestroyUnwrapper(freeOnDestroy<T> &in){ return in; }
template<typename T> T& freeOnDestroyUnwrapper(freeOnDestroy<typename std::decay<T>::type> &in){ return in; }
Then, calls can be made using the unwrapper:
int main(void){
C c(15);
V v(1);
freeOnDestroy<C> f_c(15);
foo(freeOnDestroyUnwrapper(c));
foo(freeOnDestroyUnwrapper(v));
foo<C>(freeOnDestroyUnwrapper(f_c));
foo(freeOnDestroyUnwrapper(f_c));
foo(freeOnDestroyUnwrapper(f_c));
return 0;
}
Or, to make this less verbose, we can alter foo so it does this for us:
template<typename T>
void _foo(T in){
for(int i = 0; i < 5; i++) cout << in[i] << ' ';
cout << '\n';
}
template<typename... Ts>
void foo(Ts&&... args){
_foo(freeOnDestroyUnwrapper(args)...);
}
And then call it as normal:
int main(void){
C c(15);
V v(1);
freeOnDestroy<C> f_c(15);
foo(c);
foo(v);
//foo<C>(f_c); // This now doesn't work!
foo(f_c);
foo(f_c);
return 0;
}
This seems to work for any number of arguments foo may have (of different templates, if needed), and seems to behave appropriately when foos input is a reference (which does not occur in my context, but would be good for the sake of making this solution generic).
I'm not convinced that this is the best solution, or that it generalizes to every case, plus, having to double all declarations is a bit cumbersome, and opaque to most IDEs autocomplete features. Better solutions and improvements are welcome!

Is there a better/safe way to cast non-const reference of shared_ptr to a base class?

If you have a class Base with virtual methods and a class Implementation which implements the virtual methods, is there any way to cast std::shared_ptr < Implementation > & to std::shared < Base > &? The compiler allows this for const references, but for non const references it fails as in "Case A" in the code below. Is there an easy way to do this?
If not, how safe is my workaround "questionable_cast" in Case B?
#include <iostream>
#include <memory>
class Base
{
public:
virtual void set_value(int x) = 0;
};
class Implementation : public Base
{
public:
Implementation() : m_value(0) { }
void set_value(int x) override
{
m_value = x;
}
int get_value() const
{
return m_value;
}
private:
int m_value;
};
void do_something(std::shared_ptr<Base>& base)
{
base->set_value(5);
/// Code like this makes the non-const argument necessary
base = std::make_shared<Implementation>();
}
template <class T, class U>
std::shared_ptr<T>& questionable_cast(std::shared_ptr<U>& u)
{
/// This code is here to assure the cast is allowed
std::shared_ptr<T> tmp = u;
(void)tmp;
return *reinterpret_cast<std::shared_ptr<T>*>(&u);
}
int main()
{
std::shared_ptr<Implementation> a = std::make_shared<Implementation>();
// The following line causes a compiler error:
// invalid initialization of reference of type ‘std::shared_ptr<Base>&’ ...
// do_something(a);
// do_something(std::dynamic_pointer_cast<Base>(a));
// This is the workaround
do_something(questionable_cast<Base>(a));
std::cerr << "a = " << a->get_value() << std::endl;
return 0;
}
Two obvious solutions to the problem as originally asked: 1. Make do_something take a const reference to a shared_ptr (or a shared_ptr by value). 2. Create a named shared_ptr and pass a reference to that: Eg
int main()
{
std::shared_ptr<Implementation> a = std::make_shared<Implementation>();
std::shared_ptr<Base> b = a; // This conversion works.
do_something(b); // Pass a reference to b instead.
return 0;
}
Your questionable_cast function is a violation of the strict aliasing rules, and invokes undefined behaviour. It's quite likely to work in initial tests, and then a new release of the compiler will crank up the optimization a notch, and it will fail during a demo.
To handle the case where do_something changes the pointer:
int main()
{
std::shared_ptr<Implementation> a = std::make_shared<Implementation>();
std::shared_ptr<Base> b = a; // This conversion works.
do_something(b); // Pass a reference to b instead.
const auto aa = std::dynamic_pointer_cast<Implementation>(b);
if (aa)
a = aa;
else
; // Handle the error here
return 0;
}
If do_something guarantees to return a pointer of the same derived type, even if it doesn't return the same pointer, wrap it in a template function:
template <typename T>
void do_something_ex( std::shared_ptr<T>& a )
{
std::shared_ptr<Base> b = a;
do_something(b)
a = std::dynamic_pointer_cast<T>(b);
if (!a)
throw_or_assert;
}

Dynamically create a function pointer that calls a method on a given instance

I suspect this is impossible, but thought I'd ask. Say I have a class with a method:
class A {
public:
void b(int c);
};
I can make a pointer to that member function:
void (A::*ptr)(int) = &A::b;
(someAInstance.*ptr)(123);
I can also abuse function pointers and make a pointer that takes the A argument directly (I don't know if this is safe, but it works on my machine):
void (*ptr2)(A*, int) = (void (*)(A*, int))&A::b;
(*ptr2)(&someAInstance, 123);
What I want is to somehow curry the A argument, and create a function pointer that just takes an int, but calls the A::b method on a particular A instance I've predefined. The A instance will stay constant for that particular function pointer, but there may be several function pointers all pointing to the same A::b method, but using different A instances. For example, I could make a separate wrapper function:
A* someConstantA = new A;
void wrapper(int c) {
someConstantA->b(c);
}
void (*ptr3)(int) = &wrapper;
Now I can use ptr3 without knowing which particular A it's dispatching the call to, but I had to define a special function to handle it. I need a way to make pointers for any number of A instances, so I can't hardcode it like that. Is this in any way possible?
Edit: Should've mentioned, I'm trapped in C++03 land, and also can't use Boost
Don't create a wrapper function, create a wrapper functor. This allows you to encapsulate whatever state you want to (e.g. an A*) in a callable object.
class A {
public:
void b(int c) {}
};
struct wrapper {
A* pA;
void (A::*pF)(int);
void operator()(int c) { (pA->*pF)(c); }
wrapper(A* pA, void(A::*pF)(int)) : pA(pA), pF(pF) {}
};
int main () {
A a1;
A a2;
wrapper w1(&a1, &A::b);
wrapper w2(&a2, &A::b);
w1(3);
w2(7);
}
If you have a sufficiently new compiler (e.g. gcc 4.2+), it should include TR1, where you could use std::tr1::bind:
#include <cstdio>
#include <tr1/functional>
class A {
public:
void b(int c) {
printf("%p, %d\n", (void*)this, c);
}
};
int main() {
A* a = new A;
std::tr1::function<void(int)> f =
std::tr1::bind(&A::b, a, std::tr1::placeholders::_1); // <--
f(4);
delete a;
return 0;
}
It is also doable in pure C++03 without TR1, but also much more messier:
std::binder1st<std::mem_fun1_t<void, A, int> > f =
std::bind1st(std::mem_fun(&A::b), a);
You could also write your own function objects.
Note that, in all the above cases, you need to be very careful about the lifetime of a since that is a bare pointer. With std::tr1::bind, you could at least wrap the pointer in a std::tr1::shared_ptr, so that it can live just as long as the function object.
std::tr1::shared_ptr<A> a (new A);
std::tr1::function<void(int)> f =
std::tr1::bind(&A::b, a, std::tr1::placeholders::_1);
If you are using C++11, you might use a lambda (untested code):
template<typename T, typename A>
std::function<void(A)> curry(T& object, void (T::*ptr)(A))
{
return [](A a) { (object.*ptr)(std::forward<A>(a)); }
}
I'd be using Boost::bind for this.
Basically:
class A
{
int myMethod(int x)
{
return x*x;
}
};
int main(int argc, char* argv[])
{
A test();
auto callable = boost::bind(&A::myMethod, &A, _1);
// These two lines are equivalent:
cout << "object with 5 is: " << test.myMethod(5) << endl;
cout << "callable with 5 is: " << callable(5) << endl;
return 0;
}
I think that should work. I'm also using auto in here to deduce the type returned by boost::bind() at compile-time, which your compiler may or may not support. See this other question at stackoverflow for an explanation of the return type of bind.
Boost supports back to Visual Studio 2003 (I think) and this all this will work there, though you'll be using BOOST_AUTO I think. See the other question already linked for an explanation.
What you want to do is not possible.
To see why, assume that it is possible - the function pointer must point to a function somewhere in your executable or one of its libraries, so it must point to a function that knows which instance of A to call, much like your wrapper function. Because the instance of A is not known until runtime, you'd have to create those functions at runtime, which isn't possible.
What you're trying to do is possible in C++03, as long as you're happy to pass around a function object rather than a function pointer.
As others have already given solutions with C++11 lambdas, TR1 and boost (all of which are prettier than the below), but you mentioned you can't use C++11, I'll contribute one in pure C++03:
int main()
{
void (A::*ptr)(int) = &A::b;
A someAInstance;
std::binder1st<std::mem_fun1_t<void,A,int> > fnObj =
std::bind1st(std::mem_fun(ptr), &someAInstance);
fnObj(321);
};
I've worked something out with a template Delegate class.
// T is class, R is type of return value, P is type of function parameter
template <class T, class R, class P> class Delegate
{
typedef R (T::*DelegateFn)(P);
private:
DelegateFn func;
public:
Delegate(DelegateFn func)
{
this->func = func;
}
R Invoke(T * object, P v)
{
return ((object)->*(func))(v);
}
};
class A {
private:
int factor;
public:
A(int f) { factor = f; }
int B(int v) { return v * factor; }
};
int _tmain(int argc, _TCHAR* argv[])
{
A * a1 = new A(2);
A * a2 = new A(3);
Delegate<A, int, int> mydelegate(&A::B);
// Invoke a1->B
printf("Result: %d\n", mydelegate.Invoke(a1, 555));
// Invoke a2->B
printf("Result: %d\n", mydelegate.Invoke(a2, 555));
_getch();
delete a1;
delete a2;
return 0;
}