I was wondering if it is possible to have ADL select the function template defined in the namespace of the class of one of the arguments (or in some other well defined place) in a situation when other function templates are visible. I have a motivating example that follows, and although I know the way around for that particular case (I discuss it below), the question in general seems to make sense.
I thought kind of cool to avoid using friend declarations but rather delegate work to methods, and thus came up with
namespace n
{
struct a
{
auto swap(a& a2) -> void;
};
auto swap(a& a1, a& a2) -> void
{
a1.swap(a2);
}
}
auto main(void) -> int
{
n::a a1, a2;
using std::swap;
swap(a1,a2); // use case 1
n::swap(a1,a2); // use case 2
}
So far, so good, both use cases work fine, but then, I added a second class with its own swap method and decided to save on boilerplate by turning the freestanding swap into a template:
namespace n
{
struct a
{
auto swap(a& a2) -> void;
};
struct b
{
auto swap(b& b2) -> void;
};
template<class T>
auto swap(T& t1, T& t2) -> void
{
t1.swap(t2);
}
}
auto main(void) -> int
{
n::a a1, a2;
using std::swap;
swap(a1,a2); // use case 1
n::swap(a1,a2); // use case 2
}
And here use case 1 breaks, the compiler complains about ambiguity with the std::swap template. If one anticipates the problem, it is possible to define swap functions rahter than methods (they will usually be friend, since they replace methods):
namespace n
{
struct a
{
friend auto swap(a& a1, a& a2) -> void;
};
struct b
{
friend auto swap(b& b1, b& b2) -> void;
};
}
Now everything works, so in the case of swap it is just enough to remember to use friend functions rahter than methods, but how about the general case? Is there any hack, however dirty, that would let the compiler unambiguously select n::foo<a> (or some other foo<a> under our control) in a situation where other template<class T> foo are visible, either in the global namespace or because of some using clause, especially if the latter are not ours to modify?
The culprit here is not just that you write using std::swap, but fundamentally that you have provided your own unrestricted function template swap that will give an overload resolution error with std::swap whenever namespace std is being considered during name lookup (either by an explicit using directive, or by ADL).
To illustrate: just leaving out the using std::swap will rescue you in this case
Live On Coliru
auto main() -> int
{
n::a a1, a2;
swap(a1,a2); // use case 1
n::swap(a1,a2); // use case 2
}
But suppose that you refactor your classes a and b into class templates b<T> and b<T>, and call them with a template argument from namespace std (e.g. std::string), then you get an overload resolution error:
Live On Coliru
#include <iostream>
#include <string>
namespace n
{
template<class>
struct a /* as before */;
template<class>
struct b /* as before */;
}
auto main() -> int
{
n::a<std::string> a1, a2; // oops, ADL will look into namespace std
swap(a1,a2); // use case 1 (ERROR)
n::swap(a1,a2); // use case 2 (OK)
}
Conclusion: if you define your own version of swap with the same signature as std::swap (as far as overload resolution is concerned), always qualify calls to it in order to disable ADL.
Tip: better yet, don't be lazy, and just provide your own swap function (not function template) for each class in your own namespace.
See also this Q&A where a similar mechanism is explained for why it is a bad idea to provide your own begin and end templates and expect them to work with ADL.
I know I must look silly to be answering my own question, but the fact of posting it, and the discussion, really brought some new understanding to me.
In retrospection, what should have struck me in the first place is the sequence
using std::swap;
swap(a1,a2);
It's so old-hat, and it clearly must be wrong, since using it repeatedly requires one to copy-paste the algorithm (of using using and then swapping). And you should not copy-paste, even if the algorithm is a two-liner. So what can be done better about it? How about turning it into a one-liner:
stdfallback::do_swap(a1,a2);
Let me provide the code that allows this:
namespace stdfallback
{
template<class T>
auto lvalue(void) -> typename std::add_lvalue_reference<T>::type;
template <typename T>
struct has_custom_swap
{
template<class Tp>
using swap_res = decltype(swap(lvalue<Tp>(),lvalue<Tp>()));
template <typename Tp>
static std::true_type test(swap_res<Tp> *);
template <typename Tp>
static std::false_type test(...);
static const bool value = decltype(test<T>(nullptr))::value;
};
template<class T>
auto do_swap(T& t1, T& t2) -> typename std::enable_if<has_custom_swap<T>::value,void>::type
{
swap(t1,t2);
}
template<class T>
auto do_swap(T& t1, T& t2) -> typename std::enable_if<!has_custom_swap<T>::value,void>::type
{
std::swap(t1,t2);
}
}
In the solution you find a SFINAE-based traits class has_custom_swap whose value is true or false depending on whether an unqualified call to swap for lvalues of the instantiation type is found (for that need the lvalue template, similar to declval but resolving to l-value rather than r-value), and then two overloads of a do_swap method for the case when the custom swap is present, and when it is not. They have to be called different than swap, otherwise the one calling the unqualified custom swap does not compile, because it is itself ambiguous to the swap it tries to call.
So maybe we should consider using this pattern instead of the established using?
(To give proper credit, the traits solution was inspired by http://blog.quasardb.net/sfinae-hell-detecting-template-methods/)
Related
I want to test whether a type can be passed to some function, but I'd like to use ADL on the function lookup and include a function from a certain namespace.
Consider this code:
#include <utility>
#include <vector>
template<class T>
concept Swappable = requires(T& a, T& b)
{
swap(a,b);
};
static_assert(Swappable<std::vector<int>>); // #1
static_assert(Swappable<int>); // #2
#1 succeeds, it finds std::swap because std is an associated namespace of std::vector<int>. But #2 fails, a built-in type has no associated namespace.
How would I write something like:
template<class T>
concept Swappable = requires(T& a, T& b)
{
using std::swap; // illegal
swap(a,b);
};
AFAIK, you're not allowed to use a using-declaration inside a requires-expression.
(NOTE Although there is a perfectly fine standard C++ concept for this, std::swappable, this example uses swap for exposition only. I'm not particularly looking to test whether something is actually swappable, I'm just trying to find a way to implement such a concept where a customization function has a default implementation in a known namespace, but might have overloads in an associated namespace.)
EDIT As a workaround, I can implement the concept in a separate namespace where the names are pulled in. Not too happy about it but it works.
namespace detail
{
using std::swap;
template<class T>
concept Swappable = requires(T& a, T& b)
{
swap(a,b);
};
}
// and then either use it
using detail::Swappable;
// or redefine it
template<class T>
concept Swappable = detail::Swappable<T>;
You can put it inside a lambda:
template<class T>
concept Swappable = []{
using std::swap;
return requires(T& a, T& b) { swap(a, b); };
}();
Avoid using old using-based idioms. Instead, use the customization point equivalents like ranges::swap.
That is, you should not require users to use using-based idioms in their code. Provide a customization point object that does what it needs to. The operator() overloads/templates can be constrained to create the effect of the using idiom without requiring the user to actually invoke using.
ranges::swap is a good example of how this gets done.
Interesting, the below code works well again:
#include <concepts>
template <typename T, typename U = T>
concept Swappable = requires(T&& a, U&& b) {
std::swap(a, b);
};
int main() {
static_assert(Swappable<int>);
static_assert(Swappable<int, int>);
return 0;
}
I see an example from cppconference, but I could not get expected results. Cpp reference. See code here:
template <typename T, typename U = T>
concept Swappable = requires(T&& a, U&& b) {
swap(std::forward<T>(a), std::forward<U>(b));
swap(std::forward<U>(b), std::forward<T>(a));
};
int main() {
static_assert(!Swappable<int>); // Wrong, int is definately swappable!
static_assert(!Swappable<int, int>); // Wrong, int is definately swappable!
return 0;
}
I am almost certain that what I'm looking for cannot be done without reflection, which is not yet in the language. But occasionally I'm getting surprised with exceptional answers in SO, so let's try.
Is it possible to deduce the "common_base" of two types that have a common shared base class, so the following would be possible (pseudo code! -- there is no common_base_t in the language, this is the magic I'm trying to achieve):
template<typename T1, typename T2>
const common_base_t<T1, T2>& foo(const T1& a1, const T2& a2) {
if(a1 < a2) return a1;
return a2;
}
Note that a1 and a2 above do not share a common_type, just by being siblings (sharing the same base) thus we cannot use the ternary operator.
Note also that changing the above return type to const auto& doesn't do the trick (it would not compile: inconsistent deduction for auto return type).
Here is a the naïve implementation, requiring the caller to state the expected return type:
template<typename R>
const R& foo(const auto& a1, const auto& a2) {
if(a1 < a2) return a1;
return a2;
}
Then we can call it with:
MyString1 s1 = "hello"; // MyString1 derives from std::string
MyString2 s2 = "world"; // MyString2 also derives from std::string
std::cout << foo<std::string>(s1, s2); // ok we return const lvalue ref
// pointing to one of the above objects
There are many reasons for why this probably cannot be achieved without providing the expected return value. But maybe it could be achieved somehow?
The standard library's std::common_reference<> is tantalizingly close to what you want, and arguably what your foo() function should be using, as it clearly expresses the desired semantics:
template<typename T1, typename T2>
std::common_reference_t<const T1&, const T2&> foo(const T1& a1, const T2& a2) {
if(a1 < a2) return a1;
return a2;
}
Unfortunately, it doesn't work out of the box for this specific use-case, as it cannot detect common bases unless one of the types derives from the other.
However, you can give it a hint by specializing std::common_type. Like so:
namespace std {
template<>
struct common_type<MyString1, MyString2> {
using type = std::string;
};
}
And it will "just work". You can see it in action here: https://gcc.godbolt.org/z/e3PrecPac.
Edit:
It's worth mentioning that, depending on your circumstances, you could also create a general purpose specialization of std::common_type for all types that derive from a given base:
struct SomeBase {};
namespace std {
template<std::derived_from<SomeBase> T1, std::derived_from<SomeBase> T2>
struct common_type<T1, T2> {
using type = SomeBase;
};
}
However, I would thread lightly with this. It's a potentially very broad and wide-ranging partial specialization. It could easily lead to ambiguities, especially if done more than once.
I can think of three approaches.
#1 is waiting for/using reflection.
#2 is using std::tr2::direct_bases and std::tr2::bases from way back. This is going to be a pain if you want to be able to handle "the common base is not the direct base, nor is it unique".
Doing this requires a metaprogramming library, and you end up with something like:
template<class Lhs, class Rhs>
struct common_base< Lhs, Rhs,
std::enable_if_t< always_true< extract_if_unique_t<common_direct_bases_t<Lhs, Rhs>> > >
> {
using type = extract_if_unique_t<common_direct_bases_t<Lhs, Rhs>>;
};
and it gets complex, with writing a bunch of metaprogramming boilerplate.
#3 is providing a canonical list of bases you are looking for as common bases, and searching for them as possible bases of your types. Often this is a good idea, as it means uninvolved implementation detail types don't derail you (the open-closed principle).
For the last one, I'd just do a is_base_of filter on the list of canonical bases in order for both types, then grab the first one in both lists.
template<template<class...>class Op, class List>
struct filter;
template<class Lhs, class Rhs>
struct intersect_lists;
template<class List>
struct front;
template<class...>
struct types {};
using canonical_bases = types<A,B,C,D>; // in order
template<class Derived>
struct BaseTest {
template<class Base>
using result = std::is_base_of_t< Base, Derived >;
};
template<class Lhs, class Rhs>
using canonical_common_base_of =
front_t< intersect_lists_t<
filter_t<BaseTest<Lhs>::template result, canonical_bases>,
filter_t<BaseTest<Rhs>::template result, canonical_bases>
>>;
with another few dozen lines of metaprogramming (or use an existing metaprogramming to reproduce something equivalent).
As an example, I want to use a constraint to ensure that the function isinf is implemented for a template parameter T. If T is one of float, double, long double or an integral type, this can be done in the following way:
#include <cmath>
template <typename T>
concept Test = requires (T a) {
std::isinf(a);
};
However, I also want to use this constraint for custom, non-standard data types for which I implement my own isinf function. This function is not contained in the std namespace, so I tried the following instead:
#include <cmath>
template <typename T>
concept Test = requires (T a) {
using std::isinf;
isinf(a);
};
This does not work since every statement in the requires clause should be a valid requirement and using std::isinf is not a "requirement" at all.
I see two workarounds to this problem:
Move the using std::isinf; clause to the global namespace. But this introduces isinf to the global namespace, which I'd like to avoid.
Encapsulate the using std::isinf; clause with the concept definition in a namespace named ABC, then add using ABC::Test; directly after the namespace. This seems a little bit weird.
Is there a better solution?
The way this sort of thing works in Ranges is by creating a Customization Point Object. This closely mirrors your second option (we stick a using-declaration in a custom namespace) except we also provide an mechanism for users to call the correct isinf without having to write a bunch of the same kind of boilerplate themselves.
A customization point object for isinf would look something like this:
namespace N {
// make our own namespace
namespace impl {
// ... where we can bring in std::isinf
using std::isinf;
struct isinf_t {
// our type is constrained on unqualified isinf working
// in a context where std::isinf can be found
template <typename T>
requires requires (T t) {
{ isinf(t) } -> std::same_as<bool>;
}
constexpr bool operator()(T t) const {
// ... and just invokes that (we know it's valid and bool at this point)
return isinf(t);
}
};
}
// we provide an object such that `isinf(x)` incorporates ADL itself
inline constexpr auto isinf = impl::isinf_t{};
}
And now that we have an object, a concept follows directly:
template <typename T>
concept Test = requires (T t) {
N::isinf(t);
}
This is precisely how the range concept is specified.
This should work. I'm not that comfortable with c++20 concepts so I cannot guarantee that the syntax is correct.
namespace impl {
using std::isinf;
template<class T>
auto adl_isinf(T t) -> decltype(isinf(t));
// { return isinf(t); } // implementation not necessary depending on whether
// requires is an unevaluated context
}
template <typename T>
concept Test = requires (T a) {
impl::adl_isinf(a);
};
I have the following code:
#include <iostream>
#include <vector>
using namespace std;
struct A{};
struct B: public A {};
template <typename T>
void foo(const T& obj) { cerr << "Generic case"<< endl;}
void foo(const A& a) {
cerr << "Specific case" << endl;
}
int main() {
vector<int> v;
foo(v);
B b;
foo(b);
A a;
foo(a);
}
Output is
Generic case
Generic case
Specific case
Why is it that foo(const A& a) is not being chosen for the B object ?
Curiously enough, if I removed the templated method and just have the following:
#include <iostream>
#include <vector>
struct A{};
struct B: public A {};
//template <typename T>
//void foo(const T& obj) { cerr << "Generic case"<< endl;}
void foo(const A& a) {
cerr << "Specific case" << endl;
}
int main() {
B b;
foo(b);
A a;
foo(a);
}
The code compiles and the output is:
Specific case
Specific case
Why is the presence of the templated method making such a difference?
Edit: How can I force the compiler to choose the free method for classes derived from A in the presence
of the templated method?
No conversion is necessary for the call to foo(const B&) which the template instantiation yields thus it is the better match.
When a function call is seen by the compiler, every base function template has to be instantiated and is included in the overload set along with every normal function. After that overload resolution is performed. There is also SFINAE, which allows an instantiation of a function template to lead to an error (such a function would not be added to the overload set). Of course, things aren't really that simple, but it should give the general picture.
Regarding your edit: There is only one method to call. What else could there be as output?
Yes, it is a bit surprising but inheritance and template don't mix so well when it come to overload resolution.
The thing is, when evaluating which overload should be selected, the compiler chooses the one that necessitates the least conversions (built-in to built-in, derived-to-base, calls to non-explicit constructors or conversion operators, etc...). The ranking algorithm is actually pretty complex (not all conversions are treated the same...).
Once the overloads are ranked, if the two top-most are ranked the same and one is a template, then the template is discarded. However, if the template ranks higher than the non-template (less conversions, usually), then the template is selected.
In your case:
for std::vector<int> only one overload matches, so it is selected.
for A two overloads match, they rank equally, the template one is discarded.
for B two overloads match, the template rank higher (no derived-to-base conversion required), it is selected.
There are two work-arounds, the simplest is to "fix" the call site:
A const& ba = b;
foo(ba);
The other is to fix the template itself, however this is trickier...
You can hardcode that for classes derived from A this is not the overload you wish for:
template <typename T>
typename std::enable_if<not std::is_base_of<A, T>::value>::type
foo(T const& t) {
std::cerr << "Generic case\n";
}
However this is not so flexible...
Another solution is to define a hook. First we need some metaprogramming utility:
// Utility
template <typename T, typename Result = void>
struct enable: std::enable_if< std::is_same<T, std::true_type>::value > {};
template <typename T, typename Result = void>
struct disable: std::enable_if< not std::is_same<T, std::true_type>::value > {};
And then we define our hook and function:
std::false_type has_specific_foo(...);
template <typename T>
auto foo(T const& t) -> typename disable<decltype(has_specific_foo(t))>::type {
std::cerr << "Generic case\n";
}
And then for each base class we want a specific foo:
std::true_type has_specific_foo(A const&);
In action at ideone.
It is possible in C++03 too, but slightly more cumbersome. The idea is the same though, an ellipsis argument ... has the worst rank, so we can use overload selection on another function to drive the choice of the primary one.
#pmr's answer explains why the templated function is preferred in your example. To force the compiler to pick your overload instead, you can make use of SFINAE to drop the templated function from the overload set. Change the templated foo to
template <typename T>
typename std::enable_if<!std::is_base_of<A, T>::value>::type
foo(const T& obj) { cerr << "Generic case"<< endl;}
Now, if T is A or a class derived from A the templated function's return type is invalid and it will be excluded from overload resolution. enable_if is present in the type_traits header.
Imagine I'm writing some container template or something. And the time comes to specialize std::swap for it. As a good citizen, I'll enable ADL by doing something like this:
template <typename T>
void swap(my_template<T>& x, my_template<T>& y) {
using std::swap;
swap(x.something_that_is_a_T, y.something_that_is_a_T);
}
This is very neat and all. Until I want to add an exception specification. My swap is noexcept as long as the swap for T is noexcept. So, I'd be writing something like:
template <typename T>
void swap(my_template<T>& x, my_template<T>& y)
noexcept(noexcept(swap(std::declval<T>(), std::declval<T>())))
Problem is, the swap in there needs to be the ADL-discovered swap or std::swap. How do I handle this?
I think I would move it into a separate namespace
namespace tricks {
using std::swap;
template <typename T, typename U>
void swap(T &t, U &u) noexcept(noexcept(swap(t, u)));
}
template <typename T>
void swap(my_template<T>& x, my_template<T>& y)
noexcept(noexcept(tricks::swap(std::declval<T>(), std::declval<T>())))
{
using std::swap;
swap(x.something_that_is_a_T, y.something_that_is_a_T);
}
Alternatively you can move the whole code up into tricks and delegate to there.
There is a similar problem for return types:
// Want to be compatible with both boost::tuple and std::tuple
template<typename Tuple>
auto first(Tuple&& tuple)
-> /* ??? */
{
// Introduce name into scope
using std::get;
// but ADL can still pick boost::get for boost::tuple
return get<0>(std::forward<Tuple>(tuple));
}
Using decltype( get<0>(std::forward<Tuple>(tuple)) ) isn't correct as get isn't in scope.
Possible workarounds are:
Introducing a dummy template (get in my example, swap in your case) in the enclosing scope; this includes putting the using std::swap declaration in the enclosing namespace, with the drawback of polluting the namespace.
Use of a type trait: typename std::tuple_element<0, typename std::remove_reference<Tuple>::type>::type (actually this one is problematic but for reasons that don't belong here) in my example, and a potential is_nothrow_swappable<T>::value in your case. Specializations then allow the template to be extended for other types if need be.
Rather than declaring but not defining a function template, which seems likely to cause confusion, I would write my own type trait (which is what should probably be in the standard library, anyway). Following the lead of the standard library, I would define something like the following:
#include <type_traits>
#include <utility>
namespace adl {
using std::swap;
template<typename T, typename U>
struct is_nothrow_swappable : std::integral_constant<
bool,
noexcept(swap(std::declval<T &>(), std::declval<U &>()))
> {
};
} // namespace adl
We have to define our own namespace to import std::swap into (to avoid giving it to everyone), but of course, if it were in the standard library that wouldn't be necessary because they can already make unqualified calls to swap.
C++17 has solved this particular use case with std::is_nothrow_swappable: http://en.cppreference.com/w/cpp/types/is_swappable