Call to template base constructor is ambiguous - c++

The following code
template<class T>
struct Bar
{
Bar(T& myT){}
Bar(const Bar&) = delete;
};
template<class T>
struct Foo: public T,
public Bar<T>
{
Foo(): Bar<T>(*this){}
};
class Baz{};
int main()
{
Foo<Baz> myFoo;
return 0;
}
Gives me this error:
error: call to constructor of 'Bar<Baz>' is ambiguous
How can I fix this?
(Seems simple, I'm sure there's a duplicate somewhere, but I couldn't find it... all questions I found with "ambiguous constructor" stuff had to do with overloaded constructors, and this seems different to me.)

Deleted constructors participate in overload resolution. This is in order to ensure that the compilation really fails if a program attempts to use a deleted constructor. See this answer for more details.
The relevant section in the C++11 standard is 8.4.3/2:
A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed.
[ Note: This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member
to the function. It applies even for references in expressions that are not potentially-evaluated. If a function
is overloaded, it is referenced only if the function is selected by overload resolution. —end note ]
You can solve your problem by making the constructor call unambiguous:
template<class T>
struct Foo: public T,
public Bar<T>
{
Foo(): Bar<T>(static_cast<T &>(*this)){}
};

You have two constructors in Bar<Baz>:
Bar(Baz& );
Bar(const Bar& );
The fact that the second is deleted doesn't matter for the purposes of overload resolution. You are trying to construct it from a Foo<Baz>&... which is both a Baz and a Bar<Baz>, so both overloads apply - and the compiler can't prefer one over the other, so gives you the ambiguous error. Here's a simpler example with no templates that demonstrates the same issue:
struct A { };
struct B { };
struct C : A, B { };
void foo(A& ) { }
void foo(B& ) { }
int main() {
C c;
foo(c); // error: call of overloaded ‘foo(C&)’ is ambiguous
}
To break the ambiguity, could just explicitly tell the compiler which overload to use with casting:
Foo(): Bar<T>(static_cast<T&>(*this)) {} // will call Bar(Baz&)

Related

Overload resolution and shared pointers to const

I'm converting a large code to use custom shared pointers instead of raw pointers. I have a problem with overload resolution. Consider this example:
#include <iostream>
struct A {};
struct B : public A {};
void f(const A*)
{
std::cout << "const version\n";
}
void f(A*)
{
std::cout << "non-const version\n";
}
int main(int, char**)
{
B* b;
f(b);
}
This code correctly writes "non-const version" because qualification conversions play a role in ranking of implicit conversion sequences. Now take a look at a version using shared_ptr:
#include <iostream>
#include<memory>
struct A {};
struct B : public A {};
void f(std::shared_ptr<const A>)
{
std::cout << "const version\n";
}
void f(std::shared_ptr<A>)
{
std::cout << "non-const version\n";
}
int main(int, char**)
{
std::shared_ptr<B> b;
f(b);
}
This code doesn't compile because the function call is ambiguous.
I understand that user-defined deduction-guide would be a solution but it still doesn't exist in Visual Studio.
I'm converting the code using regexp because there are thousands of such calls. The regexps cannot distinguish calls that match the const version from those that match the non-const version. Is it possible to take a finer control over the overload resolution when using shared pointers, and avoid having to change each call manually? Of course I could .get() the raw pointer and use it in the call but I want to eliminate the raw pointers altogether.
You could introduce additional overloads to do the delagation for you:
template <class T>
void f(std::shared_ptr<T> a)
{
f(std::static_pointer_cast<A>(a));
}
template <class T>
void f(std::shared_ptr<const T> a)
{
f(std::static_pointer_cast<const A>(a));
}
You can potentially also use std::enable_if to restrict the first overload to non-const Ts, and/or restrict both overloads to Ts derived from A.
How this works:
You have a std::shared_ptr<X> for some X which is neither A nor const A (it's either B or const B). Without my template overloads, the compiler has to choose to convert this std::shared_ptr<X> to either std::shared_ptr<A> or std::shared_ptr<const A>. Both are equally good conversions rank-wise (both are a user-defined conversion), so there's an ambiguity.
With the template overloads added, there are four parameter types to choose from (let's analyse the X = const B case):
std::shared_ptr<A>
std::shared_ptr<const A>
std::shared_ptr<const B> instantiated from the first template, with T = const B.
std::shared_ptr<const B> instatiated from the second template, with T = B.
Clearly types 3 and 4 are better than 1 and 2, since they require no conversion at all. One of them will therefore be chosen.
The types 3 and 4 are identical by themselves, but with overload resolution of templates, additional rules come in. Namely, a template which is "more specialised" (more of the non-template signature matches) is preferred over one less specialised. Since overload 4 had const in the non-template part of the signature (outside of T), it's more specialised and is therefore chosen.
There's no rule that says "templates are better." In fact, it's the opposite: when a template and a non-template have the same cost, the non-template is preferred. The trick here is that the template(s) have lesser cost (no conversion required) than the non-template (user-defined conversion required).
Tag dispatching can solve the issue.
It follows a minimal, working example:
#include <iostream>
#include<memory>
struct A {};
struct B : public A {};
void f(const A*, std::shared_ptr<const A>)
{
std::cout << "const version\n";
}
void f(A*, std::shared_ptr<A>)
{
std::cout << "non-const version\n";
}
template<typename T>
void f(std::shared_ptr<T> ptr)
{
f(ptr.get(), ptr);
}
int main(int, char**)
{
std::shared_ptr<B> b;
f(b);
}
As you can see, you already have what you need to create your tag: the stored pointer.
Anyway, you don't have to get it and pass it around at the call point. Instead, by using an intermediate function template, you can use it as a type to dispatch your calls internally. You don't even have to name the parameter if you don't want to use it.
The reason for the ambiguity is that both std::shared_ptr<A> and std::shared_ptr<const A> can be constructed from std::shared_ptr<B>, due to the converting constructor template. See [util.smartptr.shared.const]:
shared_ptr(const shared_ptr& r) noexcept;
template<class Y> shared_ptr(const shared_ptr<Y>& r) noexcept;
18   Remarks: The second constructor shall not participate in overload
resolution unless Y* is compatible with T*.
Thus both overloads have the exact same rank, specifically a user-defined conversion, which leads to the ambiguity during overload resolution.
As a workaround we just need an overload for non-const types:
template <class U, std::enable_if_t<!std::is_const_v<U> && std::is_convertible_v<U*, A*>, int> = 0>
void f(std::shared_ptr<U> a) {
f(std::static_pointer_cast<A>(a));
}
With that we hide the user-defined conversion, making this overload a better match.

When does unique_ptr require a complete type?

In the code below function f() can call the operator bool() and operator *() member functions of unique_ptr<C> for the incomplete class C. However when function g() tries to call those same member functions for unique_ptr<X<C>>, the compiler suddenly wants a complete type and tries to instantiate X<C>, which then fails. For some reason unique_ptr<X<C>>::get() does not cause template instantiation and compiles correctly as can be seen in function h(). Why is that? What makes get() different from operator bool() and operator *()?
#include <memory>
class C;
std::unique_ptr<C> pC;
C& f() {
if ( !pC ) throw 0; // OK, even though C is incomplete
return *pC; // OK, even though C is incomplete
}
template <class T>
class X
{
T t;
};
std::unique_ptr<X<C>> pX;
X<C>& g() {
if ( !pX ) throw 0; // Error: 'X<C>::t' uses undefined class 'C'
return *pX; // Error: 'X<C>::t' uses undefined class 'C'
}
X<C>& h() {
if ( !pX.get() ) throw 0; // OK
return *pX.get(); // OK
}
class C {};
Here's a contrived and simplified example, using only our own types:
class Incomplete;
template <class T>
struct Wrap {
T t;
};
template <class T>
struct Ptr {
T* p;
void foo() { }
};
template <class T>
void foo(Ptr<T> ) { }
int main() {
Ptr<Incomplete>{}.foo(); // OK
foo(Ptr<Incomplete>{}); // OK
Ptr<Wrap<Incomplete>>{}.foo(); // OK
::foo(Ptr<Wrap<Incomplete>>{}); // OK!
foo(Ptr<Wrap<Incomplete>>{}); // error
}
The problem is, when we make an unqualified call to foo, as opposed to a qualified call to ::foo or calling the member function Ptr<T>::foo(), we're triggering argument-dependent lookup.
ADL will look in the associated namespaces of template types in class template specializations, which will trigger implicit template instantiation. Template instantiation needs to be triggered in order to perform ADL lookup because, for instance, Wrap<Incomplete> could declare a friend void foo(Ptr<Wrap<Incomplete >> ) which would need to be invoked. Or Wrap<Incomplete> might have dependent bases whose namespaces need to also be considered. Instantiation at this point makes the code ill-formed because Incomplete is an incomplete type and you can't have a member of an incomplete type.
Getting back to the original question, the calls to !pX and *pX invoke ADL which leads to the instantation of X<C> which is ill-formed. The call to pX.get() does not invoke ADL, which is why that one works fine.
See this answer for more details, also CWG 557.
It's not the unique_ptr that requires the complete type, it's your class X that does.
std::unique_ptr<C> pC;
You don't actually do any allocation yet for C so the compiler doesn't need to know the specifics of C here.
std::unique_ptr<X<C>> pX;
Here, you use C as a template type for X. Because X contains an object of type T which is C here the compiler needs to know what to allocate when X is instantiated. (t is an object and thus instantiated on construction). Change T t; to T* t; and the compiler wouldn't complain.
Edit:
This does not explain why h() compiles, yet g() does not.
This example compiles fine:
#include <memory>
class C;
std::unique_ptr<C> pC;
C& f() {
if (!pC) throw 0; // OK, even though C is incomplete
return *pC; // OK, even though C is incomplete
}
template <class T>
class X
{
T t;
};
std::unique_ptr<X<C>> pX;
typename std::add_lvalue_reference<X<C>>::type DoSomeStuff() // exact copy of operator*
{
return (*pX.get());
}
void g() {
if ((bool)pX) return;
}
class C {};
int main()
{
auto z = DoSomeStuff();
}
Which makes it even more interesting as this mimics the operator* but does compile. Removing the ! from the expression also works. This seems to be a bug in multiple implementations (MSVC, GCC, Clang).

Reference lost on forwarding (and no auto-conversion to save me) - why?

I'm writing a Factory for producing instances of subclasses of a base class using their name, and using this (templated) factory with my class Foo. Never mind the entire code, but essentially, the factory has a map from string to functions creating instances; and a template parameter controls which arguments these functions take. In my case, the ctor of Foo, and any subclass of foo, takes a const Bar&, and that's what the variadic template for ctor arguments consist of.
I have:
template<typename SubclassKey, typename T, typename... ConstructionArgs>
class Factory {
public:
using Instantiator = T* (*)(ConstructionArgs&&...);
private:
template<typename U>
static T* createInstance(ConstructionArgs&&... args)
{
return new U(std::forward<ConstructionArgs>(args)...);
}
using Instantiators = std::unordered_map<SubclassKey,Instantiator>;
Instantiators subclassInstantiators;
public:
template<typename U>
void registerSubclass(const SubclassKey& subclass_id)
{
static_assert(std::is_base_of<T, U>::value,
"This factory cannot register a class which is is not actually "
"derived from the factory's associated class");
auto it = subclassInstantiators.find(subclass_id);
if (it != subclassInstantiators.end()) {
throw std::logic_error("Repeat registration of the same subclass in this factory.");
}
subclassInstantiators.emplace(subclass_id, &createInstance<U>);
}
};
And by popular demand, here's also...
class Foo {
using FooFactory = Factory<std::string, Foo, const Bar&>;
private:
static FooFactory& getTestFactory() {
static FooFactory kernel_test_factory;
return kernel_test_factory;
}
//...
public:
//...
template <typename U>
static void registerInFactory(const std::string& name_of_u) {
Foo::getTestFactory().registerSubclass<U>(name_of_u);
}
Bar bar;
Foo(const Bar& bar_) : bar(bar_) { };
virtual ~Foo() {}
// ...
};
class NiceFoo : public Foo {
// no ctors and dtors
};
Unfortunately, for some reason, when I call
I get a complaint about the ctor expecting a const Bar& while the argument list I supposedly provide in my createInstance is actually a const Bar.
Questions:
Why is the reference "disappearing"?
Am I doing something wrong? Should I be approaching this matter differently?
GCC error output:
/home/joeuser/myproj/../util/Factory.h(36): error: no instance of constructor "NiceFoo::NiceFoo" matches the argument list
argument types are: (const Bar)
detected during:
instantiation of "T *util::Factory<SubclassKey, T, ConstructionArgs...>::createInstance<U>(ConstructionArgs &&...) [with SubclassKey=std::string, T=Foo, ConstructionArgs=<const Bar &>, U=NiceFoo]"
(59): here
instantiation of "void util::Factory<SubclassKey, T, ConstructionArgs...>::registerSubclass<U>(const SubclassKey &) [with SubclassKey=std::string, T=Foo, ConstructionArgs=<const Bar &>, U=NiceFoo]"
/home/joeuser/myproj/../Foo.h(79): here
instantiation of "void Foo::registerInFactory<U>(const std::string &) [with U=NiceFoo]"
/home/joeuser/myproj/NiceFoo.cpp(122): here
There are two problems in your code: the immediate one, and a fundamental one.
The immediate one is that NiceFoo does not declare any constructors. You claimed that "it inherits Foo's constructors," but that's not the case in the code you've shown. Inheriting constructors would be achieved by this:
class NiceFoo : public Foo {
public:
using Foo::Foo;
}
Without the using declaration, you just have a class with no constructors declared (it will have the copy, move, and parameterless ones generated by default, but no new ones).
There is also a fundamental issue in your design: You're trying to use template parameters of a class template in perfect forwarding. That doesn't work; perfect forwarding relies on template argument deduction, which only happens with function templates.
In other words, this: ConstructionArgs&&... does not create forwarding references, but plain old rvalue references. In the concrete case you've presented, it does not really matter, because ConstructionArgs is const Bar & and reference collapsing makes it work out. But if you had included a value type (and not reference type) among the constructor arguments, createInstance would have been using plain rvalue references and initialisation from an lvalue would have been impossible.
The correct solution to this would be to have ConstructionArgs mirror exactly what the constructor of T expects—in other words, drop the && from use of ConstructionArgs everywhere, and use std::move instead of std::forward inside createInstance. One second thought, the std::forward should be able to stay and do the right thing; basically equivalent to a no-op for lvalue references, and to a std::move for values and rvalue references.

conversion operator with template functions

I have a class with a conversion operator to std::string. It works great with everything except with functions receiving std::basic_string<T> (templated on T).
#include <string>
struct A{
operator std::string(){return std::string();}
};
void F(const std::basic_string<char> &){}
template<typename T> void G(const std::basic_string<T> &) {}
int main(){
A a;
F(a); // Works!
G(a); // Error!
return 0; // because otherwise I'll get a lot of comments :)
}
The error I receive is
error: no matching function for call to 'G(A&)'
note: candidate is:
note: template<class T> void G(const std::basic_string<_CharT>&)
Now, I know I can define G as a friend in the struct A and it'll work, but my problem is with a lot of stl functions that already exist and receive std::basic_string<T> (for example, the operator<< printing function, or comparison operators, or many other functions.
I would really like to be able to use A as if it was an std::string. Is there any way to do this?
I would really like to be able to use A as if it was an std::string. Is there any way to do this?
Yes, but are you sure you really want this? The solution is:
struct A : public std::string {
};
but recall that std::string doesn't have a virtual destructor and therefore, cannot be used polymorphically. You have been warned!!!
A str() is a far better solution and allows you to be explicit when you want to pass your A to a function taking a std::basic_string<T>.
The compiler cannot infer that far; you'll either have to explicitly call the cast operator or to explictly specify the template parameter :
G(static_cast<std::string>(a));
G<char>(a);
To understand why the compiler can't do both user-defined conversion and template argument deduction, let's take this example :
template<typename T>
struct Number {
Number(double n) {};
Number(int n) {};
};
struct A{
operator Number<double>(){return Number<double>(1.);}
operator Number<int>(){return Number<int>(1);}
};
template<typename T> void G(Number<T>& number) { }
int main(){
A a;
G(a); // What do I do ?!
return 0;
}
What the compiler should do in that case ?
User defined conversions are not taken into consideration when performing template argument deduction.
Explicit specialization of G will work.
G<char>(a);

templates copy constructor errors

Here is a minimal code that shows the problem:
template<typename To, typename From> To convert(const From& x);
struct A
{
int value;
template<typename T> A(const T& x) { value = convert<A>(x).value; }
};
struct B : public A { };
int main()
{
B b;
A a = b;
}
It gives me: undefined reference to 'A convert<A, B>(B const&)'
As expected, as I removed the default copy constructor. But if I add this line to A:
A(const A& x) { value = x.value; }
I get the same error. If I try to do this way: (adding a template specialization)
template<> A(const A& x) { value = x.value; }
I get: error: explicit specialization in non-namespace scope 'struct A'.
How to solve it?
My compiler is MinGW (GCC) 4.6.1
EDIT:
The convert functions converts from many types to A and back again. The problem is that don't make sense writing a convert function from B to A because of the inheritance. If I remove the line that calls convert from A it just works. The idea is to call convert for all times that do't inherit from A, for these, the default constructor should be enough.
As for as I understand, when b is passed, as b is not an object of A, copy constructor is not called, instead the template constructor is called.
However, if an object of the derived class is passed, you want the copy constructor of A to be called.
For this, there is one solution using <type_traits> (c++0x):
#include <type_traits>
template<typename To, typename From> To convert(const From& x);
struct A
{
int value;
template<typename T> A(const T& x,
const typename std::enable_if<!std::is_base_of<A,T>::value, bool>::type = false)
{ value = convert<A>(x).value; }
A(){}
};
struct B : public A { };
int main()
{
B b;
A a = b;
}
The template is disabled why an object of a class derived from A is passed, so the only available constructor is the copy constructor.
You can solve it by defining the convert function :
template<typename To, typename From> const To& convert(const From& x)
{
return x;
}
As expected, as I removed the default copy constructor.
No; while you do need to replace the default copy constructor, its omission causes a different sort of problem (and only if you have the sort of calling code that needs it).
The error you report:
undefined reference to 'A convert<A, B>(B const&)
is a linker error. It is telling you that you don't actually have a convert function anywhere.
error: explicit specialization in non-namespace scope 'struct A'
You were right the first time about how to put back the default copy constructor. However, that's still irrelevant to the linker error.
Well, the "undefined reference" should be easily solved by linking in the implementation of the function!
NOTE: as things stand, returning a copy will trigger a stack overflow.
EDIT: IMO, your design is flawed, you have moved the construction logic outside of A into convert; rather than this, you should provide specific conversion constructors in A. It's either that or some boost::enable_if trick to disable the conversion constructor if the passed in type is derived from A (you can use one of the type_traits for that). For example, if you can construct an A from an int, provide the specific constructor in A itself.