I have a very simple problem: Somewhere there is a function
int size (const C & c)
which is found, at least, by argument-dependent name lookup. Now the problem:
struct B
{
int size () { /* ... */ }
void doSomething (const C & c)
{
int x = size (c); // <----------- problem!
// ...
}
}
This does not work, as name lookup stops after having found the member function.
What do I have to write in the indicated line such that not the member function is tried to be called, but that, rather, the compiler does whatever it would do if the member function did not exist?
Note that the solution is not writing ::size
, as this prevents argument-dependent name lookup and only works if I know where size
is declared.
Further complication:
I know that for each relevant type T
for which I use the below templated member function B::doSomething
, somewhere there will be a function
int size (const T & t)
which is found, at least, by argument-dependent name lookup. B
looks as follows:
struct B
{
int size () { /* ... */ }
template<class T>
void doSomething (const T & t)
{
int x = size (t); // <----------- problem!
// ...
}
}
I want the non-member function to be called (which I am sure it exists, but which I cannot be sure about where it lives).
The answer is YES.
Non-member functions should go in other files (all together or grouped according to similarity). That's the convention here in North America, but conventions differ. Prototype just needs go into header file so you can include it wherever you use it.
class A { double calculate_parameter(double t); double get_result(double x) { double sum = 0; for (int i = 0; i < data_size; i++) { sum = sum + integrate( to_data[i], from_data[i], 1, [this](double x) { return this->calculate_parameter(x); } ); } return sum; } };
This is a well-known problem, and its solution is equally well known. I'm surprised it has not been mentioned yet. If you have a non-member function, such as this:
class C;
size_t size( C const &c );
You can make name-lookup find it in preference to a member function with a using
declaration:
struct B {
size_t size();
void foo( C const &c ) {
using ::size;
size_t sz = size(c);
}
};
When the compiler sees the call to size(c)
, it starts in the innermost scope and searches outwards for something named size
. Without the using
declaration, the compiler would have found the member-function in class scope before the non-member in the global namespace, but the using
declaration changes this. The innermost scope is the function itself, and the using declaration is found before the member function.
The beauty of this is that you still get argument-dependent lookup (ADL) because the actual call to size(c)
is unqualified. This means that you can use it in a template:
template <class T>
void foo( T const &c ) {
using ::size;
size_t sz = size(c);
}
... and even if the correct size
function is in another namespace, it'll be found by ADL. The using
declaration simply needs to reference some size
function, not necessarily the one you actually want. It would be normal to have a default implementation somewhere that perhaps calls the member. The next version of C++ standard (C++17) is almost certain to have a std::size
function that does exactly that. Once that is widely available, you'll be able to write
using std::size;
size_t sz = size(c);
At the moment, you can either provide your own default implementation, such as this:
template <class C>
constexpr auto size( C const &c ) -> decltype(c.size()) {
return c.size();
}
... or you can continue to reference the version for C
, and rely on ADL finding the right one.
If you can't rename your own member function, you can employ a dirty trick:
static inline int dirty_trick(C const & c)
{
return size(c);
}
void B::doSomething(C const & c)
{
int x = dirty_trick(c);
// ...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With