Question

Given a custom type, the following fragment shows the common approach for allowing a function to automatically select a user provided overload specific to the type, or a generic implementation of a function from the standard library if not.

// assume std::foo is a real function template returning an int
namespace a {
  struct b { };    
  int foo(b& ab) { ... }
}

int bar(a::b& ab)
{
  using std::foo;
  return foo(ab);
}

This approach will automatically pick a::foo in preference to std::foo if it exists.

My question is, is it possible to achieve a similar behaviour when the call in question is part of the initializer list of a constructor?

struct bar2
{
  bar2(a::b& ab);
  int i;
};

bar2::bar2(a::b& ab)
  : i{foo(ab)} // want a::foo if available, else std::foo
{ }

Obviously putting using std::foo in the constructor body is too late. However if I put it before the constructor definition I introduce std::foo to the global namespace which is also not desirable.

Is there any way to have the best of both worlds in this situation?

Was it helpful?

Solution

According to Can a using statement appear in a constructor initialization list? one work around is to use a private static function like so:

struct bar2
{
  bar2(a::b& ab);
  int i;
  private:
  static int wrapper(a::b& f)
  {
      using std::foo;
      return foo(f);
  }
};

bar2::bar2(a::b& ab)
  : i{wrapper(ab)} // want a::foo if available, else std::foo
{ }

In this case, you can preserve the benefits of the initialization list without having to move the initialization to the body of the constructor. The OP in the question linked above claims that it doesn't provide ADL, but it seems to work for me. To test, simply remove:

int bar(foo f)
{
    std::cout << "custom.\n";
    return 0;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top