I have a templated class that wraps a vector. I'm trying to store unique_ptrs in this class, and it works fine. However, when I mark the void add(const T& elem) function as virtual, my compiler (clang) tells me that I'm making a "call to implicitly-deleted copy constructor" for unique_ptr.
I understand that unique_ptrs can't be copied, so that's why I created the void add(T&& elem) function. I just don't know why marking the other add function as virtual causes the compiler error.
Thanks for your time.
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
template <typename T>
class ContainerWrapper {
private:
vector<T> vec;
public:
ContainerWrapper() : vec() {
}
//Marking this as virtual causes a compiler error
void add(const T& elem) {
vec.push_back(elem);
}
void add(T&& elem) {
vec.push_back(std::move(elem));
}
T removeLast() {
T last = std::move(vec.back());
vec.pop_back();
return last;
}
};
int main() {
ContainerWrapper<unique_ptr<string>> w;
w.add(unique_ptr<string>(new string("hello")));
unique_ptr<string> s = w.removeLast();
cout << *s << endl;
}
This is most likely due to ContainerWrapper being a template. With templates, the compiler most often won't even check member functions as long as you don't call them. However, marking it virtual forces the function to be present (you might also even get a link error).
You can possibly take a look at this post : When the virtual member functions of a template class instantiated?.
The problem here is that std::unique_ptr has its copy constructor marked as =delete. This means that the vec.push_back(elem) call inside the add(T const&) overloaded member function will not compile when being called with a std::unique_ptr. The compiler will realize this as soon as that member function is being instantiated.
The Standard has 2 relevant quotes here in 14.7.1 Implicit instantiation [temp.inst]:
6 If the overload resolution process can determine the correct
function to call without instantiating a class template definition, it
is unspecified whether that instantiation actually takes place.
10 [...] It is unspecified whether or not an implementation implicitly
instantiates a virtual member function of a class template if the
virtual member function would not otherwise be instantiated. [...]
Clause 6 states that -without the virtual keyword- the compiler is allowed but not required to instantiate both add(T const&) and add(T&&) in order to resolve which overload is the best match. Neither gcc 4.7.2 nor Clang 3.2 need the instantiation because they happen to deduce that rvalue references always are a better match for temporaries than lvalue references.
Clause 10 states that -even with the virtual keyword- the compiler is also allowed but not required to instantiate add(T const&) and add(T&&) in order to resolve which overload is the best match. Both gcc 4.7.2 and Clang 3.2 happen to the instantiate both member functions, even though they both could have deduced that the lvalue overload would never be a better match.
Note that if you make ContainerWrapper a regular class with a nested typedef unique_ptr<string> T;, then both gcc and Clang will generate errors with or without the virtual keyword because they have to generate code for both member functions. This will not be SFINAE'ed away because it the error does not happen during substitution of deduced arguments.
Conclusion: this is not a bug but a quality of implementation issue.
Related
This question already has an answer here:
Why are some functions within my template class not getting compiled?
(1 answer)
Closed 2 years ago.
This C++ code builds successfully:
void h(int *)
{
}
template <typename T>
class A
{
public:
void f()
{
T *val;
h(val);
}
};
int main()
{
A<const int> a;
}
Why?
It is undeniable that A<const int>::f() cannot work.
If you call a.f(), it fails to build as expected.
Why is an instance of A<const int> even allowed to exist then?
I'm not sure how SFINAE applies here.
I'd appreciate a C++ standard quote or a relevant link.
It's allowed to exist because it can still be useful for it to exist.
Consider std::vector, which has a one-argument overload of resize, which default-constructs new elements. Definitely useful! But it's also useful to have a std::vector of some type which isn't default-constructible, when you don't intend to resize it in that way. Forcing all member functions to be available, even those not needed by the user, would artificially restrict the applicability of a class.
There's no sfinae here. If we look closely at the declaration of the function, and not it's implementation:
template <typename T>
class A
{
public:
void f();
};
You can see that there's nothing to tell the compiler that this function should not be part of overload resolution.
If we add a return type containing an expression, this is different:
template <typename T>
class A
{
public:
auto f() -> decltype(void(h(std::declval<T*>())));
};
That's different. Now The compiler need to resolve h(T*) to perform overload resolution. If the substitution fails (the instantiation of the function declaration) then the function is not part of the set.
As for why the code still compiles, take a look at this:
void h(int *)
{
}
template <typename T>
class A
{};
template<typename T>
void f()
{
T *val;
h(val);
}
int main()
{
A<const int> a;
}
It's undeniable that f(A<const int>) cannot work
If you call f(a), it fails to build as expected.
Why is an instance of A<const int> even allowed to exist then?
The answer should become obvious now: the function is never instantiated!
The very same applies for member functions. There is no use to instantiate all member function if you don't use them.
If you look for an official statement that comfirm this behavior, then look no further than the standard itself.
From [temp.inst]/4 (emphasis mine):
Unless a member of a class template or a member template is a declared specialization, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist or if the existence of the definition of the member affects the semantics of the program; in particular, the initialization (and any associated side effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.
GCC isn't giving me an error on an example I've made where I was hoping it would:
class CannotBeCopied {
public:
CannotBeCopied(const CannotBeCopied&) = delete;
CannotBeCopied& operator=(const CannotBeCopied&) =delete;
CannotBeCopied() { }
~CannotBeCopied() { }
};
template<class T>
class FirstVector {
public:
FirstVector() {
size = 1;
data = new T[size];
}
~FirstVector() {
delete[] data;
}
FirstVector(const FirstVector& source) {
size = source.size;
data = new T[size];
for(int k=0;k!=size;k++) {
data[k] = source.data[k]; //<--I EXPECT AN ERROR HERE
}
}
private:
int size;
T* data;
};
This error doesn't happen when the copy constructor isn't use (that is, it does happen when the copy constructor is used).
Because of the template I cannot simply move the copy-ctor into a code file and have that fail when it compiles.
How can I get this to fail?
This is not SFINAE, it should not be able to instantiate the template. If the copy-ctor was itself a template method (say by putting:
template<class U=T>
on the line above, then it'd be SFINAE.
I am using GCC 4.8.1, -pedantic -Wall -Wextra of course, and -std=c++11
I was hoping to get this to fail with:
int main() {
FirstVector<CannotBeCopied> whatever;
}
I know that GCC is just being lazy and not doing work it doesn't need to, but I do not like that if I were to explicitly instantiate this template in a code file, I'd get an error. Is there a way to get the error I want?
If you don't actually create an instance of your template, the copy constructor doesn't need to be called - the template code will not even be created for CannotBeCopied, if you don't use it. Invoke the copy constructor and you will get the error:
FirstVector<CannotBeCopied> a;
FirstVector<CannotBeCopied> b = a;
Edit: You may also use explicit instantiation of the template with all it's members by adding
template class FirstVector<CannotBeCopied>;
(§14.7.2 of language specification)
Templates in C++ are only materialized when they are used.
Everything else would be too expensive.
As you may have heard, C++ templates are turing complete, so evaluating them can be is insanely expensive. IIRC there was an example somewhere of Fibonnaci<17>, which would have the compiler compute this number...
In particular this means the dead code will be eliminated, and the c++ compiler will only fail once you try to use the copy constructor.
It's not just a matter of GCC being lazy; it is affirmatively prohibited from doing what you want it to do by the standard. [temp.inst]/p1, 2, 11:
1 Unless a class template specialization has been explicitly
instantiated (14.7.2) or explicitly specialized (14.7.3), the class
template specialization is implicitly instantiated when the
specialization is referenced in a context that requires a
completely-defined object type or when the completeness of the class
type affects the semantics of the program. [...] The implicit instantiation of
a class template specialization causes the implicit instantiation of
the declarations, but not of the definitions, default arguments, or
exception-specifications of the class member functions [...]
2 Unless a member of a class template or a member template has been
explicitly instantiated or explicitly specialized, the specialization
of the member is implicitly instantiated when the specialization is
referenced in a context that requires the member definition to exist.
[...]
11 An implementation shall not implicitly instantiate a function
template, a variable template, a member template, a non-virtual member
function, a member class, or a static data member of a class template
that does not require instantiation.
This allows you to have, e.g., std::vectors of move-only types. Their copy constructors will not compile, but as long as you don't use them, a std::vector<std::unique_ptr<T>> is perfectly valid.
To force it to fail, you might use a static_assert inside FirstVector:
static_assert(std::is_copy_constructible<T>::value, "T must be copy constructible");
Note, however, that this only checks that a declaration of the copy constructor is accessible and not deleted, not that the body of the copy constructor will compile, which means that it will falsely report that std::vector<std::unique_ptr<T>> is copy constructible.
I am using VS Express 2013 trying to compile a c++ project. I've created a template class with some functions. The class and its functions are all in one header file. I've included the file, I've used the class, I've called functions from it, and despite all that visual studio won't compile the classes' functions that I'm not using. I've turned off all optimizations. Do I HAVE to use a function that I've written just to see that it compiles or not?
Here is the function:
void remove(ID id)
{
sdfgsdfg456456456456sfdsdf
}
The function shouldn't compile. And indeed the project won't compile if I do use this function, but if I don't use the function the project will compile, even if I use other functions from within this class.
Is there a fix to this? Will the same thing happen if I implement the function in a .cpp file?
Edit: I neglected to mention it is a template class. I've added that information in.
As revealed in comments, the reason this is happening is because remove() is a function in a class template. The compiler only instantiates template code if it is actually used; if you don't call remove(), it can have all the syntax errors you want and nobody will complain.
More formally, § 14.7.1 of the standard states (emphasis mine):
The implicit instantiation of a class template specialization causes
the implicit instantiation of the declarations, but not the
definitions or default arguments, of the class member functions
And later in the same section:
An implementation shall not implicitly instantiate a function
template, a member template, a non-virtual member function, a member
class, or a static data member of a class template that does not
require instantiation.
(the word "implicit" is key here; if you use explicit template instantiation, the compiler will immediately try to instantiate all members using the indicated type(s) and fail if any doesn't compile)
This is not just an optimization; you can exploit this behavior to instantiate class templates with types that only support a subset of the template's operations. For example, suppose you write a template class that will be used with types that support a bar() operation, and in addition, some will also support baz(). You could do this:
template<typename T>
class Foo
{
private:
T _myT;
public:
void bar()
{
_myT.bar();
}
void baz()
{
_myT.baz();
}
};
Now suppose you have these too:
struct BarAndBaz
{
void bar() {}
void baz() {}
};
struct BarOnly
{
void bar() {}
};
This will compile and run just fine:
void f()
{
Foo<BarAndBaz> foo1;
foo1.bar();
foo1.baz();
Foo<BarOnly> foo2;
foo2.bar();
// don't try foo2.baz()!
// or template class Foo<BarOnly>!
}
If I have a class template and I use a smart pointer to a dynamically allocated instance of a specialized instance, does that cause the entire class template to be defined by the complier or will it also wait for a member function to be called from the pointer before it is instantiated?
template <class T>
class Test {
public:
void nothing();
void operation();
static const int value;
};
template <class T>
const int Test<T>::value = 100;
template <class T>
void Test<T>::nothing() {
/* invalid code */
int n = 2.5f;
}
template <class T>
void Test<T>::operation() {
double x = 2.5 * value;
}
int main() {
std::unique_ptr<Test<int>> ptr = new Test<int>(); // mark1
ptr->operation(); // mark2
return 0;
}
Does the entire class template get instantiated at mark1?
If not does that mean this code will compile correctly and the member function Test::nothing() not be instantiated?
Does the entire class template get instantiated at mark1?
Yes. The class template is implicitly instantiated — only the class template, not all its members.
If not does that mean this code will compile correctly and the member function Test::nothing() not be instantiated?
The not doesn't imply that, rather if nothing() is not used, it is not instantited.
The full answer to this probably depends highly on what compiler you are using.
At //mark1, the compiler will notice that at least portions of the Test<int> class need to instantiated. Whether or not it does it right then, or in a later phase, is up to the compiler designer.
At //mark2, Test<int>.operation() is obviously needed, it is either marked for later instantiation or created on the spot, again depending on what the compiler designers decided.
Since Test<int>.nothing() is never referenced, the compiler has the freedom to instantiate it or not. Some older compilers blindly instantiated the entire class, but I suspect the majority of modern compilers will only instantiate what they can prove to be necessary (or at least that they can't prove is not necessary). Again, though, where that happens within the compiler depends on the way the compiler designers built the compiler.
So as it turns out for the compiler I'm using (MS Visual C++), my supposition was correct that, for the code as presented in the question, the class template member instantiation would not take place at //mark1 but rather at //mark2 and Test<int>.nothing() would not be created by the compiler.
However, it seems I left out a critical part of the issue that I was experiencing. My actual class was a part of a virtual hierarchy, and according to the MSDN help library all virtual members are instantiated at object creation. So in the example above, if both member functions, i.e. operation() and nothing(), are virtual then at //mark2 the compiler would try to generate code for both functions and the validation of nothing() would fail.
http://msdn.microsoft.com/en-us/library/7y5ca42y.aspx
http://wi-fizzle.com/howtos/vc-stl/templates.htm#t9
I have following piece of code:
It compiles without problems under gcc-3.4, gcc-4.3, intel compiler, but fails under MSVC9.
MSVC tells "use of undefined type c_traits<C>, while compiling class template member function void foo<C>::go(void) with C=short.
The point it the compiler tries to install unused member function of unused class, because
this class is just not used at all.
I can work-around the issue by specializing entire class foo instead of specializing
its member function. But the point it that specializing entire class is little bit problematic for me for different reasons.
The big question: what is right?
Is my code wrong and gcc and intel compiler just ignore the issue because they do not install foo fully, or
The code is correct and this is bug of MSVC9 (VC 2008) that it tries to install unused member functions?
The code:
class base_foo {
public:
virtual void go() {};
virtual ~base_foo() {}
};
template<typename C>
struct c_traits;
template<>
struct c_traits<int> {
typedef unsigned int_type;
};
template<typename C>
class foo : public base_foo {
public:
static base_foo *create()
{
return new foo<C>();
}
virtual void go()
{
typedef typename c_traits<C>::int_type int_type;
int_type i;
i=1;
}
};
template<>
base_foo *foo<short>::create()
{
return new base_foo();
}
int main()
{
base_foo *a;
a=foo<short>::create(); delete a;
a=foo<int>::create(); delete a;
}
Both compilers are right here; the behavior for your case is unspecified. ISO C++ 14.7.1[temp.inst]/9:
An implementation shall not implicitly instantiate a function template, a member template, a non-virtual member function, a member class or a static data member of a class template that does not require instantiation. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated.
The reasoning for this is fairly simple: a virtual function requires a vtable entry, and with virtual dispatch, it may be tricky for the compiler to determine whether a given virtual function is actually called or not. Therefore, ISO C++ permits the compilers to do such advanced analysis for the sake of generating smaller code, but does not require it of them - so, as a C++ programmer, you should always assume that all virtual functions will always be instantiated.
The removal of unused functions will occur at linking not at compilation where you are having your error. MSVC may not know who amongst all the compilation units being compiled who will ultimately call that method. It can't know until compilation is complete and until linking occurs. Naturally different compilers may be smarter about this, but I suspect this may be what is happening.
I suspect your specific compiler errors sounds like it is caused by you having only forward declared
template<typename C>
struct c_traits;
you have not fully specified the class. Did you try something as simple as:
template<typename C>
struct c_traits
{
// some default/dummy int type
};
I suspect this would at least stop the compiler from complaining.
EDIT
this is generally wrong for class
templates. Member functions of class
templates aren't supposed to be
compiled (and any errors in their
bodies aren't supposed to be
triggered) unless they're instantiated
The template is instantiated in this case in the form of:
foo<short>
The compiler will treat this as any other class who's methods have potential for external linkage. I haven't heard any special language rule that says that external linkage doesn't apply to templates...?