Let us consider following example:
#include <type_traits>
#if 1
struct X {};
struct O
{
O(X) { ; }
};
#else
struct O {};
struct X
{
operator O () { return {}; }
};
#endif
static_assert(std::is_convertible< X, O >::value);
struct S
{
void f(X) const { ; }
void f(O) { ; }
};
#include <cstdlib>
int
main()
{
S s;
s.f(X{});
return EXIT_SUCCESS;
}
Live example
It gives an error:
error: call to member function 'f' is ambiguous
When I removing const-qualifier, then the error cease to exist. Equally the same happens, if I add const-qualifier to the second overloading of f. I.e. if both overloadings are equally const-qualified, then all is OK.
Why is it so?
My compiler is clang 3.8.
Member functions have implicit parameter this.
So to call one of the functions f the compiler needs either to convert this to type const S * or to convert X to O.
Neither conversion regarding all parameters is better. So the compiler issues an error.
Why is it so?: The reason here is because the const-ness of the s object itself is also considered in overload resolution. Since s is non-const it would require adding const to the implicit this pointer to call the const f. Calling the non-const f is an exact match for the this pointer but requires an implicit conversion from X to O via O's converting constructor.
Mark B & Vlad from Moscow answer why, I just reply how can you call them.
you should add explicit to avoid compiler implicit conversion
#include <iostream>
struct X {};
struct O
{
explicit O(X) { ; }
O() = default;
O(O const &) = default;
O(O &&) = default;
};
struct S
{
void f(X) const { ; }
void f(O) { ; }
};
#include <cstdlib>
int main()
{
S s;
s.f(X{});
return EXIT_SUCCESS;
}
EDIT
if your type O is in 3party lib
you can add a template to do this.
#include <iostream>
using namespace std;
struct X {};
struct O {
O(X) {
;
}
O() = default;
O(O const&) = default;
O(O&&) = default;
};
struct S {
void f(const X) const {
cout << "X" << endl;
}
void f(O) {
cout << "O" << endl;
}
};
#include <cstdlib>
template<typename TA, typename TB>
void myCall(TA a, TB b) {
((const TA &&)a).f(b);
}
template<>
void myCall(S a, O b) {
a.f(b);
}
template<>
void myCall(S a, X b) {
((const S)a).f(b);
}
int main() {
S s;
myCall(s, X());
//s.f(X());
return EXIT_SUCCESS;
}
Related
Consider the following code which works as expected:
#include <iostream>
#include <functional>
struct foo
{
std::function<int()> get;
};
struct bar
{
int get()
{
return 42;
}
};
int main()
{
foo f;
bar b;
f.get = std::bind(&bar::get, &b);
if (f.get())
std::cout << "f.get(): " << f.get() << std::endl;
return 0;
}
Now, let's assume that bar::get() is a const member function:
#include <iostream>
#include <functional>
struct foo
{
std::function<int()const> get;
};
struct bar
{
int get() const
{
return 42;
}
};
int main()
{
foo f;
bar b;
f.get = std::bind(&bar::get, &b);
if (f.get())
std::cout << "f.get(): " << f.get() << std::endl;
}
Using GCC 9.2, this snipped throws the following compiler error:
main.cpp:6:31: error: field 'get' has incomplete type 'std::function<int() const>'
6 | std::function<int()const> get;
| ^~~
In file included from /usr/local/include/c++/9.2.0/functional:59,
from main.cpp:2:
/usr/local/include/c++/9.2.0/bits/std_function.h:128:11: note: declaration of 'class std::function<int() const>'
128 | class function;
| ^~~~~~~~
I fail to understand why foo::get has incomplete type.
Could somebody point me towards the right direction for understanding this behavior and "fixing" it accordingly?
I have the need to bind a const member function to a function pointer.
int()const is an abominable type.
std::function<int()const> is not a type, because it doesn't match the only defined specialisation
namespace std {
template< class R, class... Args >
class function<R(Args...)> { ... };
}
Just use std::function<int()>.
The const bit only makes sense for member functions. You've already bound bar::get to an instance b to save it as a std::function.
As mentioned by #KamilCuk:
The constness is checked at std::bind, not at std::function
You don't need to pass explicit const to std::function. Just use your older prototype: std::function<int()>. It will work if you don't have const overload (that mean, you have either one of these int bar::get() or int bar::get() const) for the same member function (Otherwise, you need to type cast explicity).
Actually, your function (int bar::get() const) will be having a signature like this (behind the scenes):
// int bar::get() const
int get(const bar *const this)
{
return 42;
}
// int bar::get()
int get(bar *const this)
{
return 42;
}
If you have overloads and want to bind specific member function, you can do something like this:
typedef int(bar::*fptr)(void) const; // or remove const
std::bind((fptr)&bar::get, &b );
See this:
#include <iostream>
#include <functional>
#include <vector>
struct foo
{
std::function<int()> get;
};
struct bar
{
int get()
{
return 42;
}
int get() const
{
return 50;
}
};
int main()
{
foo f;
bar b;
typedef int (bar::*fptr)(void);
typedef int (bar::*fcptr)(void) const;
f.get = std::bind((fptr)&bar::get, &b);
if (f.get())
std::cout << "f.get(): " << f.get() << std::endl;
f.get = std::bind((fcptr)&bar::get, &b);
if (f.get())
std::cout << "f.get(): " << f.get() << std::endl;
}
Output:
f.get(): 42
f.get(): 50
std::bind does not pass through constness to the callable. Therefore, the following would work:
struct foo {
std::function<int()> get;
// ^ note there is no 'const'
};
With a normal class. For example:
class A {
public:
int a;
std::string b;
A() {}
~A() {}
}
We can do:
A x;
x.a = 1;
x.b = "hello";
But now I don't want to do like above. I want to access n_index-th attribute of object. For example pseudo like x.get<2>() (or x.set<2>(...)) like x.b.
How can do that? Have any template for that.
Beside if I want code like that
int number = 2;
x.get<number>()
Any problem with constexpr?
I think the closest you can get is using boost::fusion.
An example would be
#include <boost/fusion/adapted.hpp>
#include <boost/fusion/sequence.hpp>
#include <boost/mpl/int.hpp>
#include <iostream>
class A {
public:
int a;
std::string b;
A() {}
~A() {}
};
BOOST_FUSION_ADAPT_STRUCT(A,
(int, a)
(std::string, b)
)
using namespace boost::fusion;
int main()
{
A x;
x.a = 1;
x.b = "hello";
std::cout << at<boost::mpl::int_<0>>(x) << '\n';
std::cout << at<boost::mpl::int_<1>>(x) << '\n';
at<boost::mpl::int_<0>>(x) = 5;
at<boost::mpl::int_<1>>(x) = std::string("World");
std::cout << at<boost::mpl::int_<0>>(x) << '\n';
std::cout << at<boost::mpl::int_<1>>(x) << '\n';
}
If you want to set several values at the same time when you create the object, you could use a multi-parameter constructor. For example, let's imagine you have this:
class A {
public:
int a;
std::string b;
A() {}
~A() {}
};
You could add a constructor that sets a and b:
class A {
public:
int a;
std::string b;
A() {}
A(int a, std::string b) {
this->a = a;
this->b = b;
}
~A() {}
};
That way, you can create your object and set a and b with :
A a = A(1, "hello");
There is no ready-made way of setting the n-th attribute of your object. You could make one, but I would very, very highly recommend that you don't. Like I said above, if you reorder your attributes, then you will have to rework everything.
If you really, really want to make your life very, very, very much harder, a very ugly and error-prone way of doing this would be like :
template<class T>
void A::setNth(int nth, const T& value) {
switch (nth) {
case 1: a = value; break;
case 2: b = value; break;
// You should #include <stdexcept> to use runtime_error, or you could handle the exception in some other way.
default: throw std::runtime_error("A::setNthAttribute : Value of nth is out of bounds.");
}
}
For the getter:
template<class T>
void A::getNth(int nth, T& valueOut) {
switch (nth) {
case 1: valueOut = a; break;
case 2: valueOut = b; break;
default: throw std::runtime_error("A::getNthAttribute : Value of nth is out of bounds.");
}
}
You would use these methods like this:
A a;
a.setNth(1, 2); // put 2 into a
int i;
a.getNth(1, i); // put a into i
Just writing this code send shivers down my spine. Please, never write what I just wrote. Chuck Norris will kill yoU agfh
86sd asdsa dDASD8!4.
What you are considering is in fact possible, but a bit of a headache. I would approach it by creating a template getter and setter for every member that one can set or get, and then having a template method that takes an int and sets or gets the appropriate property. The getters/setters would have to be specialized for the correct type, and throw an error for other types. This method would have to use a switch to return the right member:
class bar {
private:
int a;
std::string b;
template<T>
T getA() {
// error
}
template<T>
T getB() {
// error
}
template<T>
void setA(const T& A) {
// error
}
template<T>
void setB(const T& B) {
// error
}
template <> std::string getB(); // specialization
template <> int getA();
template <> void setB(const std::string&);
template <> void setA(int);
public:
template<T>
T get(int what) {
switch(what) {
case 1:
return getA();
case 2:
return getB();
default:
// handle error here
break;
}
}
template<T>
void set(int what, const T& t) {
switch(what) {
case 1:
return setA<T>(t);
case 2:
return setB<T>(t);
default:
// handle error here
break;
}
}
};
bar b;
b.set<std::string>(2, "foo");
auto str = b.get<std::string>(2);
Here's an elaborate way to accomplish what you want.
#include <iostream>
#include <string>
// A namespace explicitly defined for class A.
namespace A_NS
{
// A template for members of A.
template <int> struct Member;
// Specialization for the first member.
template <> struct Member<1>
{
using type = int;
type var;
};
// Specialization for the second member.
template <> struct Member<2>
{
using type = std::string;
type var;
};
}
class A {
public:
A() {}
~A() {}
template <int N> typename A_NS::Member<N>::type get() const
{
return static_cast<A_NS::Member<N> const&>(members).var;
}
template <int N> void set(typename A_NS::Member<N>::type const& in)
{
static_cast<A_NS::Member<N>&>(members).var = in;
}
private:
// Define a type for the member variables.
struct Members : A_NS::Member<1>, A_NS::Member<2> {};
// The member variables.
Members members;
};
int main()
{
A a;
a.set<1>(10);
a.set<2>("test");
std::cout << a.get<1>() << ", " << a.get<2>() << std::endl;
}
Output:
10, test
Lets assume we have two classes
struct A
{
int x = 1;
};
struct B
{
int y = 2;
};
I want to have template that will return value of member (in a case of A I want to return value of "x", in case of B I want to return value of "y").
Example call:
const auto myVariable = f<A>();
or
A a;
const auto myVariable = f<A>(a);
I don't want to have 2 template specializations - ideally it would be one template with some kind of "if statement", but maybe it is not possible?
It may be written with C++11 (but not with C++14).
Generally how you are using templates when you have such problems - quite big template and only in one or two places you need to take values from different members - which may be deduced based of type of that variable.
PROBLEM: unnecessary it is not allowed to modify classes A and B
Why use templates at all?
int f(const A& a) { return a.x; }
int f(const B& b) { return b.y; }
Just in case you ask for the template because you want to switch between A and B at compile time...and you have a reason not to simply typedef A or B directly...
struct A
{
int x;
};
struct B
{
int y;
};
struct A1 : public A { int Get() const { return x; } };
struct B1 : public B { int Get() const { return y; } };
// Begin possible shortcut avoiding the template below:
#ifdef USE_A
typedef A1 Bar;
#endif
#ifdef USE_B
typedef B1 Bar;
#endif
// End possible shortcut.
template <class _Base>
struct CompileTimeAOrB
: public _Base
{
int Get() const
{
return _Base::Get();
}
};
#define USE_A
//#define USE_B
#ifdef USE_A
typedef CompileTimeAOrB<A1> Foo;
#endif
#ifdef USE_B
typedef CompileTimeAOrB<B1> Foo;
#endif
EDIT: Since A and B cannot be changed, introduced A1, B1 ;)
#include <iostream>
struct A
{
int value;
A() : value(2) {}
};
struct B
{
int value;
B() : value(4) {}
};
template <typename T>
int GetValue(T t)
{
return t.value;
}
int main()
{
A a;
B b;
std::cout << GetValue(a) << std::endl;
std::cout << GetValue(b) << std::endl;
return 0;
}
In order for it to work, you'd need to have the same variable or function named declared in each class you wanted this to work with.
#include <initializer_list>
#include <iostream>
namespace {
class C {
public:
C(C const &) = delete;
C(C &&) = delete;
C(int) {
std::cout << "int\n";
}
C(std::initializer_list<int>) {
std::cout << "initializer\n";
}
};
void f(C) {
}
// Compiles and prints "initializer" when called
C g() { return {0}; }
// Fails to compile
// C h() { return 0; }
} // namespace
int main() {
// Compiles and prints "initializer"
f({0});
// Fails to compile
// f(0);
}
Is it possible to construct C, a non-copyable, non-movable type, into a function parameter or function return value without invoking the initializer_list constructor?
It's only possible if you can change C so the desired constructor can be chosen instead of the initializer-list constructor, e.g. by wrapping the argument type in something that isn't convertible to the element type of the initializer-list constructor:
#include <initializer_list>
#include <iostream>
namespace {
template<class T>
struct wrap
{
T value;
};
class C {
public:
C(C const &) = delete;
C(C &&) = delete;
C(wrap<int>) {
std::cout << "int\n";
}
C(std::initializer_list<int>) {
std::cout << "initializer\n";
}
};
void f(C) {
}
// Compiles and prints "int" when called
C g() { return {wrap<int>{0}}; }
} // namespace
int main() {
// Compiles and prints "int"
f({wrap<int>{0}});
g();
}
This prints:
int
int
Can one show me an example of ADL without using templates? Never seen something like that. I mean something like here. Specifically I am interested in example in which it leads to some pitfall like in mentioned.
EDIT:
I think Tomalak's answer can be extended to pitfall. Consider this:
namespace dupa {
class A {
};
class B : public A {
public:
int c;
B() {
}
};
void f(B b) {
printf("f from dupa called\n");
}
}
void f(dupa::A) {
printf("f from unnamed namespace called\n");
}
int main()
{
dupa::B b;
f(b);
return 0;
}
Here we expect that f from unnamed namespace will be called, but instead another one is called.
I can't show you something leading to a pitfall, but I can demonstrate ADL working without templates:
namespace foo {
struct T {} lol;
void f(T) {}
}
int main() {
f(foo::lol);
}
Note that lol's type has to be a class-type; I originally tried with a built-in, as you saw, and it didn't work.
The trick to get confusion is creating an scenario where the arguments to the function are interchangeable or convertible and that ADL might pick something that might not be what you would expect. I am not sure if this is impressive or just expected:
namespace a {
struct A {};
void f( A* ) { std::cout << "a::f" << std::endl; }
}
namespace b {
struct B : ::a::A {};
void f( B* ) { std::cout << "b::f" << std::endl; }
}
void test() {
f( new b::B ); // b::f
a::A* p = new b::B;
f( p ); // a::f
}
The types are the same, but ADL will check the static type of the argument and add that namespace into the search. That in turn means that the exact static type might make different functions visible to the compiler. Things can be more confusing when there are more than one argument on which ADL or overload resolution can apply .
No templates.
Using swap() because that is the most common usage.
#include <iostream>
namespace One
{
class A {};
void swap(A& lhs, A& rhs) { std::cout << "Swap-One A\n";}
}
namespace Two
{
class A {};
void swap(A& lhs, A& rhs) { std::cout << "Swap-Two A\n";}
}
int main()
{
One::A oneA_l;
One::A oneA_r;
Two::A twoA_l;
Two::A twoA_r;
swap(oneA_l, oneA_r);
swap(twoA_l, twoA_r);
}