I am exploring the world of constexpr and have decided to create a class that should only be used in constexpr context and other compile-time constructs.
Usually, I take great care to provide all necessary overloads a class may need, for example:
template <typename T>
struct Thing
{
Thing(T value) : m_value(value) {}
T &value() & { return m_value; }
const T &value() const & { return m_value; }
T &&value() && { return std::move(m_value); }
private:
T m_value;
};
The set of overloads for Thing::value should take care of efficient access to the stored value, no unnecessary copies are made. If the Thing instance is a temporary, the stored value can even be moved out.
But what if Thing is only to be used as a constexpr type, are all these different overloads for Thing::value required or even helpful at all? Or would the following be equivalent:
template <typename T>
struct Thing
{
constexpr Thing(T value) : m_value(value) {}
constexpr T value() const;
private:
T m_value;
};
My question basically boils down to: are references helpful (more efficient) when operating in a constexpr/compile-time context only; or is passing everything by value equivalent?
My question basically boils down to: are references helpful (more efficient) when operating in a constexpr/compile-time context only; or is passing everything by value equivalent?
It's a matter of what's your actual problem and how you plan to solve it. In most of the cases (all of them?) you won't need to use references in such a context, I agree, but you can still use them if required.
Here as a minimal, working example:
const int i = 0;
template <typename T>
struct Thing {
constexpr Thing(const T &value) : m_value(value) {}
constexpr const T & value() const { return m_value; }
private:
const T & m_value;
};
int main() {
static_assert(Thing<int>{i}.value() == 0, "!");
}
See it up and running on wandbox.
So, are references helpful (more efficient) in this case? Well, it's not a matter of efficiency or whatever. To use references in such a context you have to have a good reason and the language sets a lot of limitations. They solve a specific problem, it's not your taste to decide to use references.
If your problem requires you to use references, they are there for you (and please, contact me - I'm just curious to know what's that problem!). Otherwise feel free to keep on with passing by value.
Related
I have some class A that has some const and some non-const function, together with a fitting concept, say
class A {
public:
void modify() {/* ... */}
void print() const {/* ... */}
}
template<typename T>
concept LikeA = requires (T t, const T const_t) {
{ t.modify() } -> std::same_as<void>;
{ const_t.print() } -> std::same_as<void>;
}
static_assert(LikeA<A>);
A nice thing I noticed is that for some function taking const LikeA auto &a below code is actually legal:
void use (const LikeA auto &a) {
a.print(); // fine, print is a const method
// a.modify(); // illegal, a is a const reference [at least for use(A a) itself, but this is not my point here]
}
static_assert(!LikeA<const A>);
int main() {
A a1;
use(a1); //clear, as LikeA<A> holds
const A a2;
use(a2); //not obvious, as LikeA<const A> does not hold
}
I looked into the definitions on cppreference, and I could not really explain this behaviour, I expected it to be illegal, although intuitively, this really is what I want.
Now on to my real situation: I have a holder class AHolder that returns const A& as one of its methods, and I want a fitting concept for this holder class that also applies to any other holder holding anything that satisfies LikeA, so I tried:
class AHolder {
public:
const A& getA() {return _a;}
private:
const A _a;
};
template<typename T>
concept LikeAHolder = requires (T t) {
{t.getA() } -> LikeA;
};
static_assert(LikeAHolder<AHolder>); //fails
This fails, since const A& simply doesn't satisfy LikeA, so i would love to adjust this to
template<typename T>
concept LikeAHolder = requires (T t) {
{t.getA() } -> const LikeA; //invalid syntax
};
static_assert(LikeAHolder<AHolder>);
in similar spirit of the example with the use method also accepting const A.
Is there such a syntax to require the return type of t.getA to satisfy LikeA whilst considering that the return type will be const?
Additionally, how exactly are concepts checked in the use(const LikeA auto &a) method such that it behaves like explained?
(My first question is the more important one for me)
Some possible solutions that I have considered:
Return a non-const-reference. This would make above code illegal, but of course would heavily ruin const-correctness, since _a would also have to be non-const and a user could just change the private attribute of AHolder. This is no option for me.
Have two concepts LikeA and LikeConstA. The return type then could be LikeConstA only requiring the const methods. This should work, but feels really clumsy and really not how concepts should be used, also this introduces more concepts that necessary to an end-user, who has to bother with them, etc.
In the concept LikeA, check whether the templated type T is constant (via std::is_const), and if so, don't require the non-const-methods. This works in above example, but has the undesired effect that we now simply have
class B {
public:
void print() const {/* ... */}
}
static_assert(LikeA<const B>);
(for an already adapted LikeA, of course), which also just feels wrong.
in the definition of LikeA, use std::remove_reference and std::const_cast to cast away references / constness, then check for the required functions. First, i don't know if this will always work for more complicated types, but even then, this now has the undesired effect that
static_assert(LikeA<const A>);
will be true, breaking (or at least bending) the semantics of the concept.
To summary and ensure you don't get me wrong, I would like to have a way that
does enforce const-correctness
does not use a second concept 'for the end-user'. With this I mean that it is of course okay to define auxiliary concepts or use some of the standard-library that help in defining above concept, but nothing that is actually required to use A and LikeA etc.
does not simply ignore non-const requirements for const types (as I mentioned, this would be compiler-wise okay, but semantically feels wrong)
does not define LikeA<const A> to be true
Ideally, there would just be a feature working like the already-mentioned
template<typename T>
concept LikeAHolder = requires (T t) {
{t.getA() } -> const LikeA; //invalid syntax
};
{[](const LikeA auto&){}( t.getA() )}
Note that a non-const& returning getA will pass this.
I made a lambda that does a concept check, then ensured t.getA() passes it.
void use (const LikeA auto &a)
This is shorthand for
template<LikeA A>
void use (const A&a)
and when called with a T const, it deduces A=T not A=T const. Why? Because it is "more correct" abstractly. Concretely, there are a pile of rules for how template argument type deduction works.
Revisiting lifetime extension in C++, I found out that there are some patterns that break "decomposability" of C++ expressions. For example, the following two blocks are a valid C++ code:
class NonMovable {
public:
NonMovable(NonMovable&&) = delete;
NonMovable(const NonMovable&) = delete;
NonMovable();
int Value() const;
};
template <class T>
const T& identity(const T& x) {
return x;
}
template <class T>
class A {
public:
explicit A(const T& value) : value_(value) {}
const T& GetValue() const {
return value_;
}
private:
const T& value_;
};
Correct usage:
int main() {
int retcode = identity(
identity(/*tmp1*/ A(/*tmp2*/ NonMovable{}).GetValue())).Value();
// tmp1 and tmp2 end their lifetimes here:
// their full-expression is the whole previous line
return retcode;
}
But if we decompose the first expression in main, it becomes invalid:
int main() {
auto&& a_obj = /*tmp1*/ A(/*tmp2*/ NonMovable{});
// tmp2 lifetime ends here
// oops! dereferencing dangling reference:
int retcode = identity(
identity(a_obj.GetValue())).Value();
return retcode;
// tmp1 lifetime ends here
}
My question is:
Is it possible to disable the second kind of usage?
P.S.: I'm not really sure if the second main introduces UB, because I've tested it with clang -Wlifetime, and it doesn't complain. But I still believe it is UB. In real life I've came across a similar behaviour: the code broke, emmiting UBSan warnings and segfaults if I decomposed a single expression into two separate ones.
P.P.S.: those identitys don't really matter much, if I understand object lifetimes correctly (which I now doubt)
Your analysis is correct. Without lifetime extension, all temporaries are destroyed at the end of the "full expression", i.e. the ; at the end of the line. So when you say
int retcode = A(NonMovable{}).GetValue().Value();
(comments and identity calls removed for clarity) then everything is okay; the NonMovable object is still alive at the time you ask for its value.
On the other hand, when you say
auto&& a_obj = A(NonMovable{});
then the NonMovable is destroyed at the end of the line, and the A object will be holding a dangling reference. (As an aside, auto&& just lifetime-extends the temporary A here -- you may as well just use plain auto)
My question is: Is it possible to disable the second kind of usage?
Not really, at least as far as I know. You could add a deleted A(NonMovable&&) constructor, but this would also prevent "correct" usage as in the first example. The is exactly the same issue that occurs with std::string_view (and will occur with std::span in C++20) -- essentially, your A class has reference semantics, but is referring to a temporary which has been destroyed.
So by using collective mind, in the comments under the question we've managed to come up with the following implementation of A, which might be applicable to some use cases (but not std::span or std::string_view usage):
struct Dummy;
template <class T>
class A {
public:
explicit A(const T& value) : value_(value) {}
template <class TDummy = Dummy>
const T& GetValue() const& {
static_assert(!std::is_same_v<TDummy, Dummy>,
"Stop and think, you're doing something wrong!"
"And in any case, don't use std::move on this class!");
}
const T& GetValue() && {
return value_;
}
private:
const T& value_;
};
Now, if one tries to compile the following code, he will get a descriprive error message:
int main() {
auto&& a_obj = A(NonMovable{});
// will not compile:
int retcode = identity(
identity(a_obj.GetValue())).Value();
return retcode;
}
The reason is that decltype((a_obj)) == A<NonMovable>&, so it binds to the method that produces a compile time error.
It satisfies my use cases, but, sadly, this is not a universal solution -- it depends on what one wants from class A.
I would like to refactor the accessors in following structure:
template<class T>
class ValueTime {
public:
// accessors for val:
const T& get_val() const { return val; }
template<class V> void set_val(const V& v) { val = v; }
// other accessors for tp
private:
T val;
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
};
I would like to make the accessors to the val data members more useful and intuitive, mostly from the point of view of the "standard/boost user expectations" of such structure representing a "value in time":
template<class V = T> V get_val() { return V(val); }
T& operator*() & { return val; }
const T& operator*() const & { return val; }
Now I can use the accessors this way (see the comments):
int main() {
ValueTime<double> vt;
// get_val() no longer returns const ref and also
// allows explicit cast to other types
std::chrono::minutes period{vt.get_val<int>()}; // I had to use the more pedantic static_cast<int> with the original version
// let's use operator*() for getting a ref.
// I think that for a structure like a ValueTime structure,
// it's clear that we get a ref to the stored "value"
// and not to the stored "time_point"
auto val = *vt; // reference now;
val = 42;
}
Is the getter more usueful now? Do you see anything strange or unsafe or counterintuitive in the new interface (apart from being non backward compatible, which I do not care)?
Furthermore, one doubt I still have is if it's better to implement get_val() by returning V(val) or V{val} or just val. As it is now, it works if V has an explicit constructor. What do you think about this issue?
I personally would advise you to make the interface as descriptive as possible and avoid any convenient conversions to reference of data or similar.
The reason is simply usability and maintenance. If you or somebody else are (re-)visiting code using ValueTime, when you cannot remember the precise interface, you still want to understand your code without re-visiting the definition of ValueTime.
There is a difference to members from std (such as std::vector) is that you know their definition by heart.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I remove code duplication between similar const and non-const member functions?
In the following example :
template<typename Type, unsigned int Size>
class MyClass
{
public: inline Type& operator[](const unsigned int i)
{return _data[i];}
public: inline const Type& operator[](const unsigned int i) const
{return _data[i];}
protected: Type _data[Size];
};
the const and non-const operator[] are implemented independently.
In terms of design is it better to have :
1) two independant implementations like here
2) one of the two function calling the other one
If solution 2) is better, what would be the code of the given example ?
It is a well-known and widely accepted implementation pattern, when non-const method is implemented through its const counterpart, as in
class some_class {
const some_type& some_method(arg) const
{
...;
return something;
}
some_type& some_method(arg)
{
return const_cast<some_type&>(
const_cast<const some_class *>(this)->some_method(arg));
}
};
This is a perfectly valid technique, which essentially has no comparable (in convenience) alternatives in situations when the method body is relatively heavy. The evil of const_cast is significantly smaller than the evil of duplicated code.
However, when the body of the method is essentially an one-liner, it might be a better idea to stick to an explicit identical implementation, just to avoid this barely readable pileup of const_casts.
One can probably come up with a formally better designed castless solution implemented along the lines of
class some_class {
template <typename R, typename C>
static R& some_method(C *self, arg)
{
// Implement it here in terms of `self->...` and `R` result type
}
const some_type& some_method(arg) const
{
return some_method<const some_type>(this, arg);
}
some_type& some_method(arg)
{
return some_method<some_type>(this, arg);
}
};
but to me it looks even less elegant than the approach with const_cast.
You couldn't have either implementation calling the other one without casting away constness, which is a bad idea.
The const method can't call the non-const one.
The non-const method shouldn't call the const one because it'd need to cast the return type.
Unfortunately, "constness" templates don't work but I still think it is worth considering the overall idea:
// NOTE: this DOES NOT (yet?) work!
template <const CV>
Type CV& operator[](unsigned int index) CV {
...
}
For the time being, I'd implement trivial functions just twice. If the code become any more complex than a line or two, I'd factor the details into a function template and delegate the implementation.
Let me say we have a simple programming task. But for the sake of clarity I start with few code samples.
First of all we written a some kind of data container class but for the purposes of task no matter what the class is. We just need it to behave const-correct.
class DataComponent {
public:
const std::string& getCaption() const {
return caption;
}
void setCaption(const std::string& s) {
caption = s;
}
private:
std::string caption;
};
Then let us assume we've got a generic class that behaves like facade over arbitrary incapsulated class instance. Say we overloaded member access operator (->).
template <typename T> class Component {
public:
Component() { instance = new T(); }
...
const T* operator-> () const {
return instance;
}
T* operator-> () {
// but there might be additional magic
return instance;
}
private:
T *instance;
};
At this point I should say how I want this to work:
if we're calling non-const member functions of underlying class through member access operator (component->setCaption("foo")) compilier treats non-const T* operator-> () as the best choice.
otherwise if we are trying to call const member functions of underlying class same way (component->getCaption()) compiliers selects const T* operator-> () const on the other hand.
This code sample above won't work this way so I'm curious about possibility to give compiler a behavior like that I have mentioned. Any propositions.
EDIT: Let our member access operator overloaded this way:
const T* operator-> () const { return instance; }
T* operator-> () {
cout << "something going change" << endl;
return instance;
}
And let us have a variable Component<DataComponent> c somewhere. Then on the call to c->getCaption() stdout should remain silent but on the call to c->setCaption("foo") stdout should warn us that something is going to change. VS 2010 compilier makes stdout warn us on each of these calls.
I understand that such semantics suppose that c behaves as const and non-const at the same time. But curiousity is still in my mind.
Whether a const or non-const member is invoked is determined purely by the constness of the object on which it is invoked, not by some subsequent operation. That determination is made before any consideration of the particular method you're invoking in DataComponent. You could still hack up the required functionality less directly using proxy object around DataComponent, with both const and non-const forwarding getCaption()s.
EDIT: details as requested (off the top of my head). You'll need to forward declare some of this stuff - I didn't bother as it makes it even more confusing. Do chip in with any concerns / feedback. Note that this basically assumes you can't / don't want to modify Component for some reason, but it's not a generic templated solution that can simply be wrapped around any arbitrary type - it's very heavily coupled and has a high maintenance burden.
// know they can't call a non-const operation on T, so this is ok...
const T* Component::operator->() const { return instance; }
// they might invoke a non-const operation on T, so...
DataComponent::Proxy Component::operator->() { return DataComponent.getProxy(*this); }
in class DataComponent:
struct Proxy
{
Component& c_;
DataComponent& d_;
Proxy(Component& c, DataComponent& d) : c_(c), d_(d) { }
const std::string& get_caption() const { return d_.get_caption(); }
void set_caption(const std::string& s)
{
c_.on_pre_mutator(d_);
d_.set_caption(s);
c_.on_post_mutator(d_);
}
};
then
DataComponent::Proxy DataComponent::getProxy(Component& c) { return Proxy(c, *this); }
So, this means somewhere you have to hand-code forwarding functions. It's a pain, but if you're doing this for debugging or testing it's not unreasonable. If you're doing this so you can add a lock or something, then there are probably better alternatives.