Take the 2-minute tour ×

I recently encountered a problem while trying to implement a class hierarchy with perfect forwarding constructors. Consider the following example:

struct TestBase {
  template<typename T>
  explicit TestBase(T&& t) : s(std::forward<T>(t)) {} // Compiler refers to this line in the error message

  TestBase(const TestBase& other) : s(other.s) {}

  std::string s;

struct Test : public TestBase {
  template<typename T>
  explicit Test(T&& t) : TestBase(std::forward<T>(t)) {}

  Test(const Test& other) : TestBase(other) {}

When I try to compile the code I get the following error:

Error 3 error C2664: 'std::basic_string<_Elem,_Traits,_Alloc>::basic_string(const std::basic_string<_Elem,_Traits,_Alloc> &)' : cannot convert parameter 1 from 'const Test' to 'const std::basic_string<_Elem,_Traits,_Alloc> &'

My understanding is that the compiler treats the perfect forwarding constructor as a better math than the copy constructor. See for example Scott Meyers: Copying Constructors in C++11 . In other implementations without a class hierarchy I could disable the perfect forwarding constructor from being a copy constructor through SFINAE. See for example Martinho Fernandes: Some pitfalls with forwarding constructors. When I try to apply the mentioned solution to this example I still cannot compile with the same error message.

I think one possible solution would be to avoid the perfect forwarding, take the parameters by value in the constructors and than move from them to the class variables.

So my question is if there are some other solutions to this problem or if perfect forwarding in not possible in such a case?

Update: It turned out that my question is easy to misunderstand. So I will try to clarify my intentions and the context a bit.

  • The code is complete like posted in the question. There are no other objects created or functions called. The error appeared while trying to compile the posted example.
  • The purpose of having the perfect forwarding constructor is for member initialization and not to have some kind of extra copy constructor. The reason here is to save some object copies when initializing members with temporary objects (as proposed in talks by Scott Meyers)
  • Unfortunately as it turned out perfect forwarding constructor can conflict with other overloaded constructors (in this example with the copy constructors).
  • Like the answers and comments to this question suggested: Possible solutions here would be to introduce explicit casts or having separate non-templated constructors (i.e. regarding the example having two constructors with parameters const string& and string&& respectively).
share|improve this question
Might it be that you wrote something like std::string(test) instead of std::string(test.s)? Please show us the line 130 of main.cc –  Andrey Oct 31 '12 at 15:06
You wrote s(std::forward<T>(t)) instead of s(std::forward<T>(t).s). –  avakar Oct 31 '12 at 15:09
It's generally a bad idea to mix overloads and forwarding templates. I'd make a single constructor from string and add a forwarding make_test function template. –  Kerrek SB Oct 31 '12 at 15:10
@Andrey Sorry I should have highlighted the origin of the error message. The line number 130 in main.cc refers to the perfect forwarding constructor in TestBase. I will edit my example... –  mkh Oct 31 '12 at 15:17
@avakar The parameter t should not be a object of the Test class but instead some kind of string (i.e. std::string or cont char*). I don't want the perfect forwarding constructor to be a copy constructor so I think I should not add an .s –  mkh Oct 31 '12 at 15:27

3 Answers 3

up vote 2 down vote accepted

Try changing Test(const Test& other) : TestBase(other) {} to Test(const Test& other) : TestBase(static_cast<TestBase const&>(other)) {}

The 2nd Test constructor is calling TestBase, and there are two possibilities. One of them takes anything, the other takes a TestBase. But you are passing a Test to it -- the "anything" matches better. By explicitly casting to a TestBase const&, we should be able to get the right one to match.

Another possibility might involve how Test is constructed -- maybe what you passed in matched the template constructor to Test instead? We can test this other possibility by removing the template constructor from Test and seeing if the error goes away.

If that is the case, why wouldn't the technique you linked (to disable the Test template constructor when the type deduced matches Test) work?

share|improve this answer
Your solution compiles without errors. Could there be any possible side effects while applying your solution? Usually I like to be a little bit careful when silencing errors/warnings with casts. –  mkh Oct 31 '12 at 15:34
The cast in question is a safe one. I cast a Foo const& into a FooBase const& -- something that you wanted to do implicitly, but the compiler preferred your template constructor that accepts everything. I made explicit what you wanted to implicitly happen... –  Yakk Oct 31 '12 at 15:36
Thanks for the explanation. One more question: If I now add a move constructor to Test like this: Test(Test&& other) : TestBase(std::move(other)) {}. I get the same error message again. Do you possibly also have a solution for this situation? Tanks alot! –  mkh Oct 31 '12 at 15:51
You are calling TestBase(Test&&) in your sample code. Do you see where? Now, looking at ONLY the definition of TestBase, which ctor will that call? –  Yakk Oct 31 '12 at 15:58
+1, that's a really subtle thing. Took me some staring at the monitor to realize what's going on. –  avakar Oct 31 '12 at 16:06

Let's have a closer look at the error message.

std::basic_string<...>::basic_string(const std::basic_string<...> &) :

That means it applies to a copy constructor of std::string

cannot convert parameter 1 from 'const Test' to 'const std::basic_string<..> &

Indeed, there's no way to convert from Test to std::string. However, Test has a string member, namely, std::string s;.

Conclusion: it looks like you forgot to add .s at that place. Probably, it is in s(std::forward<T>(t)).

Another possible reason is that the 1st overload of the constructor was picked instead of the 2nd for copy-constructing an instance of Test.

share|improve this answer
I don't think I forgot the .s. My idea was that the parameter t is itself some kind of string which I want to forward to the member. For example a const char* or an std::string. –  mkh Oct 31 '12 at 15:22
@mkh: Then it means that it happened somehow that T is not a string but Test. –  Andrey Oct 31 '12 at 15:25
Than my question would be how can I make the compiler stop thinking that T could possibly be a Test. I don't create any objects or call any functions. –  mkh Oct 31 '12 at 15:37
@Andrey yep -- it appears that ctor 2 in Test ends up calling ctor 1 in TestBase "unintentionally". Then they try to convert a Test into a string, which fails. –  Yakk Oct 31 '12 at 15:38

The following should work and it uses no explicit casts:

struct Test : public TestBase {
  static TestBase const& toBase(const Test& o) { return o; }

  template <typename T>

  Test(const Test& other) : TestBase(toBase(other)) {} 
share|improve this answer

Your Answer


