Selecting between conversion operators when they are ambiguous - c++

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()));
}

Related

Object rvalue propagation for member function calls

I have a struct F with a function foo that has different implementation whether F is a temporary or not
struct F{
void foo() & { std::cout << "F::foo() &" << std::endl; }
void foo() && { std::cout << "F::foo() &&" << std::endl; }
};
Another struct A has a copy of F and in its function bar calls F::foo. I want to use the correct version of F::foo(). Therefore the implementation is:
struct A{
void bar() & {
f.foo();
}
void bar() && {
std::move(f).foo();
}
F f;
};
I'm wondering if I really have to provide two implementations of A::bar(). Isn't there a smart way to use std::forward to automatically decide which F::foo() should be used?
An attempt:
struct B{
void bar() {
std::forward<F>(f).foo();
}
F f;
};
However, this does not work. It calls F::foo() && every time.
Complete example
You can use a non-member function template:
struct B{
template<typename TB>
friend void bar(TB&& self) {
std::forward<TB>(self).f.foo();
}
F f;
};
Depending on other function parameters, you might want to restrict the type of TB such that is_base_of_v<B, remove_const_t<remove_reference_t<TB>>>.
No, there is no shortcut available at this point and you will need to stick to the verbose version. But have a look at p0847, "Deducing this". Not sure what the status of this proposal is, however. From the abstract:
We propose a new mechanism for specifying or deducing the value category of an instance of a class. In other words, a way to tell from within a member function whether the object it’s invoked on is an lvalue or an rvalue, and whether it is const or volatile.

template deduction/substitution fails on smart pointers

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.

Alternative to overloading functions with derived types

Sorry for the uninformative title, I don't really know what to call what I am asking.
I want to achieve the following: Having a container of a base class type with instances of derived types, accessing the containers and calling a function overload dependent on the type of the derived object accessed. In a question earlier I asked here I learned that the static design I had in mind so far, does not work. The way I tried is this:
struct Int2TypeBase{
};
template <int v>
struct Int2Type : public Int2TypeBase
{
enum
{
value = v
};
};
void f(const Int2Type<0>&){
std::cout << "f(const Int2Type<0>&)" << "\n";
}
void f(const Int2Type<1>&){
std::cout << "f(const Int2Type<1>&)" << "\n";
}
int main(){
using namespace std;
std::vector<std::reference_wrapper<Int2TypeBase>> v;
Int2Type<0> i2t_1;
v.emplace_back(i2t_1);
Int2Type<1> i2t_2;
v.emplace_back(i2t_2);
auto x0 = v[0];
auto x1 = v[1];
f(x0.get()); // After my imagination this would have called void f(const Int2Type<0>&)
f(x1.get()); // After my imagination this would have called void f(const Int2Type<1>&)
}
Ok, so I want the correct overload of f to be selected, this however does not compile as at compile time it is unknown which type x0 and x1 actually have. But is there some alternate design that can realize this behavior?
Overloading is a static mechanism based on static types.
If you want to change behaviour dynamically based on the dynamic type of an object, C++ provides another built-in language feature for that: Virtual functions. Use them like this:
struct Int2TypeBase
{
virtual void do_f() = 0;
};
template <int v> struct Int2Type : Int2TypeBase
{
void do_f() override
{
// specific behaviour for Int2Type<v> goes here
}
/* ... */
};
void f(Int2TypeBase & x) { x.do_f(); }
Now you can call f on any base subobject and the correct behaviour is selected at runtime. In particular, f(x0.get()) and f(x1.get()) now select and dispatch to Int2Type<0>::do_f and Int2Type<1>::do_f at runtime, respectively.

What does operator()() in c++ do?

I'm new to C++11 thread , when reading a tutorial , I see a piece of code like this.
#include <thread>
#include <iostream>
using namespace std;
class background_task
{
public:
void operator()() const
{
cout<<"This is a new thread";
}
};
int main()
{
background_task f;
std::thread my_thread(f);
my_thread.join();
}
The output will be "This is new thread", but i don' really understand what does the function "operator()() const" mean?. In this case, it acts really the same with the constructor, is it right?.
And how can C++ have a syntax like that? I have search about related topic by using the search engine but no found no result.
Thanks in advanced.
void operator()() means an instance of the class with that operator can be called with function call syntax, with no return value, and without any parameters. For example:
background_task b;
b(); // prints "This is a new thread"
The operator() part indicates it is a call operator, the second set of empty parentheses () indicate the operator has no parameters. Here is an example with two parameters and a return value:
struct add
{
int operator()(int a, int b) const { return a + b; }
};
add a;
int c = a(1, 2); // c initialized to 1+2
Note that this syntax pre-dates C++11. You can create callable types (also referred to as functors) in C++03. The connection with C++11 is that the std::thread constructor expects something that can be called without arguments . This could be a plain function
void foo() {}
a static member function
struct foo {
static void bar() {}
};
an instance of a type such as background_task, a suitable lambda expression, a suitable invocation of std::bind, in short, anything that can be called without arguments.
It's just operator overloading and has nothing to do with C++11 or multi-threading. An overloaded operator is just a normal function with a funny name (this may be a bit oversimplified, but it's a good rule of thumb for beginners).
Your class has a function named (). That's all. Technically, you could as well have named the function foo or f or TwoParentheses.
Consider a simpler example:
#include <iostream>
class Example
{
public:
void operator()() { std::cout << "()"; }
void foo() { std::cout << "foo"; }
void TwoParentheses() { std::cout << "TwoParentheses"; }
};
int main()
{
Example e;
e.operator()();
e.foo();
e.TwoParentheses();
}
Now calling an overloaded operator like in this example in main, spelling out the entire .operator() part, is pretty pointless, because an overloaded operator's purpose is to make the calling code simpler. You would instead invoke your function like this:
int main()
{
Example e;
e();
}
As you can see, e(); now looks exactly as if you called a function.
This is why operator() is a special name, after all. In a template, you can handle objects with operator() and function pointers with the same syntax.
Consider this:
#include <iostream>
class Example
{
public:
void operator()() { std::cout << "Example.operator()\n"; }
};
void function() { std::cout << "Function\n"; }
template <class Operation>
void t(Operation o)
{
o(); // operator() or "real" function
}
int main()
{
Example object;
t(object);
t(function);
}
This is the reason why operator() is an important function in C++ generic programming, and is often required.
It has nothing to do with C++11, it's the function call overload operator. That means if you have a class like yours, you can create an instance of it and use as a function:
int main()
{
background_task bt;
bt();
}
The above main function should give the same result as your simple thread example.
it is operator over loading. the user provide an additional use to () operator. Example for static polymorphism. it is fearture of Object orieted program

Simple Argument Forwarding (what should my signature be?)

As an example, say I am writing a thin wrapper for a vector's push_back method.
class Foo
{
public:
void myPushBack(Bar b); // Line in question
private:
std::vector<Bar> vec;
}
void Foo::MyPushBack(bar b)
{
vec.push_back(bar);
}
main()
{
Foo f();
f.myPushBack();
}
My question is what is the correct signature for the function myPushBack? Then my next question is what would be the correct signature for the function myPushBack if vec was of type std::vector<weak_ptr<Bar>>?
Assuming that you are using C++11, you should use the perfect forwarding idiom:
template<typename T> void Foo::MyPushBack(T &&b)
{
vec.push_back(std::forward<T>(b));
}
Since it is a template, it does not matter the actual type of the vector. It will even take into account implicit conversions, such as const char* to std::string.