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?

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

3 Answers3

2

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

Mark Garcia
  • 17,424
  • 4
  • 58
  • 94
  • 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 Oct 22 '12 at 06:33
  • 1
    @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. http://en.cppreference.com/w/cpp/container/vector/operator_at – jogojapan Oct 22 '12 at 06:34
  • @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. – Mark Garcia Oct 22 '12 at 06:35
  • That settles it then. I just wanted a quick check to see if I was missing something, and I got it! Thanks everybody. – dsign Oct 22 '12 at 06:37
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.

David Stone
  • 26,872
  • 14
  • 68
  • 84
-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;

]

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • 3
    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: http://en.cppreference.com/w/cpp/container/vector/operator_at – jogojapan Oct 22 '12 at 06:23
  • @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. – iammilind Oct 22 '12 at 06:25
  • @jogojapan put it clear. Maybe I'm missing something, but without the non-const version assignments wouldn't work: 'distances->at( i, j ) = d;' – dsign Oct 22 '12 at 06:29
  • @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. – jogojapan Oct 22 '12 at 06:31
  • (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. – Quuxplusone Oct 22 '12 at 18:26
  • @Quuxplusone, the question is not about the whether const and non-const version are same or not. But, whether they both are still required or not and what's there future in C++11. It still required as it's evident in Standard library. – iammilind Oct 23 '12 at 04:01
  • @iammilind Correct; I didn't downvote Mark Garcia's answer, which said very succinctly that the antipattern is still present in C++11. I downvoted your answer because you *didn't* say that, but you *did* say you "don't believe there is a need to get rid of" the antipattern, and then pointed out that a conscientious programmer has to write not two but *four* versions— as if this were a good thing!— and *then* threw in an irrelevancy about `noexcept` (which doesn't contribute to the antipattern's combinatorial explosion; it's just another miscellaneous function-related keyword, like `virtual`). – Quuxplusone Oct 23 '12 at 04:27