2

Pre C++ 11, I often needed to implement two very-alike variants of a method to deal with const and non-const usage scenarios of the class/struct:

struct my_struct_t{ .... float_t& at( uint32_t row, uint32_t col) { return *(((float_t*)((uint8_t*)numbers+row*row_stride)) + col); } float_t const& at( uint32_t row, uint32_t col) const { return *(((float_t*)((uint8_t*)numbers+row*row_stride)) + col); } }; 

Has this changed in C++ 11?

3
  • 1
    If both variants are doing exactly same then you can keep the const variant and get away with the other one. Commented Oct 22, 2012 at 6:04
  • 1
    I don't believe your first one would work . return a reference to a non const temporary value. Commented Oct 22, 2012 at 6:14
  • @Mike Yes, the returns are flawed, I'm fixing them now. Commented Oct 22, 2012 at 6:26

3 Answers 3

2

No.
It is evident in the Standard Library (it still uses explicit const methods).

Sign up to request clarification or add additional context in comments.

4 Comments

I didn't check STL's implementation because, well, there are several STL implementations. And most of them are tweaked to support pre-C++ 11 compilers, so, they don't necessarily offer a definitive answer.
@dsign But Mark is right nevertheless, because the C++11 Standard does define the interface for the standard library, and that still provides for const/non-const versions of certain getter-type functions, e.g. en.cppreference.com/w/cpp/container/vector/operator_at
@dsign Yes. They have several implementations. But the constraints and behavior requirements must be met by every correct implementations. Now that doesn't leave much room for difference.
That settles it then. I just wanted a quick check to see if I was missing something, and I got it! Thanks everybody.
2

This had not changed in C++11, but it has changed in C++17:

T const & f() const { return something_complicated(); } T & f() { return const_cast<T &>(std::add_const(*this).f()); } 

See How do I remove code duplication between similar const and non-const member functions?

Edit

I have changed my position a few times since making this post. The text above reflects my current thinking. My previous position was to prefer const_cast for both casts, and my original position was static_cast then const_cast. const_cast is safer because the only thing it can do is add / remove const and volatile qualifiers. static_cast can accidentally cast in other ways. My original thinking was to prefer static_cast to add const as it separates the most likely 'safe' operation of adding const from the possibly dangerous operation of removing const. The version in the code above has the safe operation spelled out by std::as_const, which can do only what I want, leaving the potentially unsafe const_cast as the only thing you need to ensure you have done correctly.

1 Comment

Did you mean self.f()?
-2

I don't believe there is a need to get rid of "not implementing 2 variants".

  1. If both variants are doing different stuff, then you must have to keep them
  2. If both variants are doing the same stuff, then remove the non-const version and maintain only the const version

By the way, there are 3rd and 4th variants if one ever needs:

float_t& at( uint32_t row, uint32_t col) volatile; float_t& at( uint32_t row, uint32_t col) const volatile; 

[Note: Irrelevant but in C++11 all the variants can be added with noexcept keyword for exception related info:

float_t& at( uint32_t row, uint32_t col) noexcept; 

]

7 Comments

The point is that both versions do the same, but they return something different, typically a const-reference vs. a non-const reference, either to *this or to an internal member. A typical example is operator[] of containers: en.cppreference.com/w/cpp/container/vector/operator_at
@jogojapan, if methods are returning something different then they are not doing the same :). Returning a non-const reference is modifiable externally but a const reference is not.
@jogojapan put it clear. Maybe I'm missing something, but without the non-const version assignments wouldn't work: 'distances->at( i, j ) = d;'
@iammilind True. But the way I understand the question it's about instances of two versions of a function that return something different but perform the same operation otherwise, and how to avoid code-duplication then. The main answer (even in C++98) in my opinion is that all non-trivial operations should be performed in a separate (possibly private, non-const) function, and the two versions should only be implemented for a getter, or something similarly trivial.
(Explaining my downvote.) dsign and jogojapan are right: having const and non-const flavors of otherwise identical accessors is a really common antipattern in C++. Word games may obscure the issue, but they don't make it go away.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.