Reputation: 7160
The following definition is not allowed by my compiler as std::string
has a non trivial destructor (makes sense that teststr
can't have a trivial dtor when a member doesn't):
class teststr
{
private:
std::string _m;
public:
constexpr teststr(std::string value) : _m(value) {};
constexpr std::string m() const { return _m; }
void m(std::string value) { _m = value; }
};
However, the following equivalent (to the best of my knowledge) definition of teststr
is allowed:
template<typename T>
class test
{
private:
T _m;
public:
constexpr test(T value) : _m(value) {};
constexpr T m() const { return _m; }
void m(T value) { _m = value; }
};
typedef test<std::string> teststr;
What is it about templating the type that makes this definition allowed?
Upvotes: 5
Views: 122
Reputation:
constexpr
is more often allowed in templates because it is not generally known at template definition time whether the member satisfies the requirements of constexpr
. When a template member is declared constexpr
, it is determined at template instantiation time whether constexpr
is appropriate, and if not, it is silently dropped.
Given
template <typename T> struct test {
T val;
constexpr test(T val) : val(val) { }
};
you can have
constexpr test<int> i = 3;
because with T = int
, the constructor meets the requirements of constexpr
, but you cannot have
constexpr test<string> s = "";
because that constructor does not meet the requirements of constexpr
.
It is not a hard error to instantiate test<string>
because that would severely limit the ability to use constexpr
in templates.
From the standard (C++11):
7.1.5 The constexpr specifier [dcl.constexpr]
6 If the instantiated template specialization of a
constexpr
function template or member function of a class template would fail to satisfy the requirements for aconstexpr
function orconstexpr
constructor, that specialization is not aconstexpr
function orconstexpr
constructor. [...]
Upvotes: 5