-2

I could not figure this out, why C++ is not allowing overloading according to the return type as in the following case the three member(getter) function has different function signature and even when to store the pointer to the member function we need different mem-function pointer types like:

for instance T = std::string
using constRefPtr   = const std::string&(MyStruct::*)() const;
using constValuePtr = const std::string(MyStruct::*)() const;
using valuePtr      = std::string(MyStruct::*)() const;

I have read this similar post, where it was suggestion to have const and non-cost member functions.

Question: How could I make the following (getter)overloads work without removing constness of each member functions(if it is possible through standard C++)?

I am using C++17.

#include <iostream>
#include <string>

template<typename T> class MyStruct
{
    T m_val;
public: 
    explicit MyStruct(const T& value) 
        : m_val(value)
    {}
    const T& getVal() const {   return m_val; } // get val as const ref(no copy of member)
    const T getVal() const  {   return m_val; } // get a const member as return
    T getVal() const        {   return m_val; } // get a copy of member
};

int main()
{
    MyStruct<std::string> obj{"string"};
    const auto& val_const_ref = obj.getVal();  // overload const std::string& getVal() const
    const auto val_const = obj.getVal();       // overload const std::string getVal()  const
    auto val = obj.getVal();                   // overload std::string getVal()  const
    return 0;
}

error messages I have got:

error C2373 : 'MyStruct<T>::getVal' : redefinition; different type modifiers
note: see declaration of 'MyStruct<T>::getVal'
note: see reference to class template instantiation 'MyStruct<T>' being compiled
error C2059 : syntax error : 'return'
error C2238 : unexpected token(s) preceding ';'
error C2143 : syntax error : missing ';' before '}'
error C2556 : 'const T MyStruct<T>::getVal(void) const' : overloaded function differs only by return type from 'const T &MyStruct<T>::getVal(void) const'
1 > with
1 > [
    1 > T = std::string
        1 > ]
    1 > C:\Z Drive\CPP Programs\Visual Studio Project\Main.cc(62) : note: see declaration of 'MyStruct<std::string>::getVal'
note: see reference to class template instantiation 'MyStruct<std::string>' being compiled
error C2373 : 'MyStruct<std::string>::getVal' : redefinition; different type modifiers
note: see declaration of 'MyStruct<std::string>::getVal'
error C2059 : syntax error : 'return'
error C2238 : unexpected token(s) preceding ';'
error C2146 : syntax error : missing ';' before identifier 'T'
error C2530 : 'val_const_ref' : references must be initialized
error C2789 : 'val_const' : an object of const - qualified type must be initialized
note: see declaration of 'val_const'
Const
  • 1,306
  • 1
  • 10
  • 26
  • 5
    "*the three member(getter) function has different function signature*" Except that they don't. Return type is not a part of the signature. See [Is the return type part of the function signature?](https://stackoverflow.com/questions/290038/is-the-return-type-part-of-the-function-signature?noredirect=1&lq=1) – Yksisarvinen May 23 '19 at 14:22
  • 1
    What difference do you expect with `T` vs `const T` as a return type? – Slava May 23 '19 at 14:24
  • 2
    Why do you feel you need three flavors of `getVal` in the first place? I believe the first one - the one returning `const T&` - is quite sufficient; you should be able to use it everywhere you think you need the other two. – Igor Tandetnik May 23 '19 at 14:25
  • @Yksisarvinen That's sad that, C++ has such a decision. The link was helpful. – Const May 23 '19 at 14:26
  • 1
    @Const no it is not, making result part of signature will create more problems that it would solve (if any). – Slava May 23 '19 at 14:28
  • `why C++ is not allowing overloading according to the return type` because this is written in C++ standard. – SergeyA May 23 '19 at 14:29
  • @SergeyA *because this is written in C++ standard* That's kind of escaping from the reason. I believe there is a reason why the standard community decided to put so. – Const May 23 '19 at 14:32
  • *difference do you expect with T vs const T*: was thinking the way of calling it: `auto val = ` and `const auto val_const=` as explained/ commented in the code. – Const May 23 '19 at 14:33
  • 1
    @Const first and foremost you have 2 versions of `foobar()` that are different by result type and one calls them like this `foobar();` (ignoring the result), which one should be called? – Slava May 23 '19 at 14:34
  • @Const ok lets start with basics `auto i = 5;` does the fact that `5` is constant affects constness of `i`? – Slava May 23 '19 at 14:36
  • @Slava That makes sense. `i` could have `const` and `non-const` integers. Sorry. I misunderstood the case. – Const May 23 '19 at 14:39
  • @Const I am afraid you still do not understand properly. When you do `auto i = whatever;` you make a copy of `whatever`. The fact that original of copy is `const` or not does not matter in this case. It is your choice to make `i` const or not. It is your copy you can do whatever with it. – Slava May 23 '19 at 14:42

3 Answers3

5

You just... can't overload on return type, full stop.

You could just make two differently named functions:

T const& ref() const { return m_val; }
T val() const        { return m_val; }

Which themselves could be overloaded based on constness or &ness:

T const& ref() const { return m_val; }
T&       ref()       { return m_val; }

T val() const&       { return m_val; }
T val() &&           { return std::move(m_val); }
Barry
  • 286,269
  • 29
  • 621
  • 977
2

It is not possible. You cannot overload on return type. Overload resolution takes into account the function signature. A function signature is made up of:

  • function name
  • cv-qualifiers
  • parameter types

The standard says:

1.3.11 signature

the information about a function that participates in overload resolution (13.3): its parameter-type-list (8.3.5) and, if the function is a class member, the cv-qualifiers (if any) on the function itself and the class in which the member function is declared. [...]

(Lightly edited from Luchian Grigore's answer)

Eponymous
  • 6,143
  • 4
  • 43
  • 43
0

Question: How could I make the following (getter)overloads work without removing constness of each member functions(if it is possible through standard C++)?

Name them appropriately. And as @Slava points out, when return a copied value there no point in distinguishing between T and const T, so something like:

const T& getConstRefVal() const { return m_val; } // get val as const ref(no copy of member)
T        getVal()         const { return m_val; } // get a copy of member
Paul Evans
  • 27,315
  • 3
  • 37
  • 54
  • I think part of your question should be explanation that OP does not need that variations. – Slava May 23 '19 at 14:27