Consider the following class:
#include <vector>
template<class T>
struct my_struct {
my_struct() {}
explicit my_struct(T) {}
explicit my_struct(std::vector<T>) {}
};
int main() {
my_struct<const int> s1(1);
}
The use case is that the third constructor should only be called in some instanciations of my_struct
, and not in some other cases (e.g. with const types). It is what is done here in the main
: it is not called.
I get a compiler error (GCC, Clang, Intel). GCC error message : /usr/local/include/c++/10.2.0/bits/stl_vector.h:401:66: error: static assertion failed: std::vector must have a non-const, non-volatile value_type
In fact, it has nothing to do with std::vector
(but the compilers are pretty bad at giving us any clue). It can be reproduced with a very similar code:
class my_class {
static_assert(0, "should not be used");
};
template<class T>
struct my_struct {
my_struct() {}
explicit my_struct(T) {}
explicit my_struct(my_class) {}
};
int main() {
my_struct<int> s(1); // error
}
The problem, as I interpret it, is that once my_struct
is instanciated, it results in a concrete type, and the compiler may instanciate all its methods. In this case, it instanciates my_struct(my_class)
, so it instanciates my_class
, so we get the static error.
note: we might get "lucky" however: in the vector
case, calling only my_struct()
does not trigger the error (something to do with overload resolution I guess)
note: the way I fix the error is by templating the constructor instead of using vector
:
template<class vector_type>
my_struct(vector_type) {}
I find it ugly but have no other idea.
- Is my interpretation of what is going on correct?
- Is this behavior required / left undefined by the language? Or is it a compiler bug?
- If yes, I would call it a language defect in C++17 at least. Would you agree?
- If yes, is there a language defect report? Is it corrected in C++20?
- If no: how would you solve the problem? Is it a design problem?
- Could we expect the compilers to have, in a not too distant future, a more detailed stack trace of what is going on? At least mentionning why it needs to instanciate a type that is never called by the concrete class at hand.