Trailing return type

Started by
7 comments, last by AthosVG 8 years, 1 month ago

Alright so as this is really bugging me, despite having found a 'solution' (i.e. throw the impl in the header), I figured I'd give this a try.

In some occassions, I implement a begin and end method in order to be able to use for-each style for loops. Now on previous occassions, these happened to be template classes, in which I preferred to keep the method implementations in the header files, so I never ran into the following issue.

Using a trailing return type, the following spits out an error once attempting to compile:

Header:


auto end()->decltype(m_Messages.end());

Cpp:


auto Foo::end()->decltype(m_Messages.end())
{
    return m_Messages.end();
}

With the following errors:

... 'left of '.end' must have class/struct/union'

'int Foo::end(void)' overloaded function differs only be return type from 'std::vector[....]' Foo::end'

'Foo::end: redefinition, different basic types'

Which, quite obviously, leads to me believe that m_Messages.end() is not being recognized. The same happens for begin.

It should be noted that simply throwing the implementation in the header file does allow it to compile.

I'm wondering what I'm missing here, especially since I also tried to just return m_Messages (as a test), which did compile. What puzzles me even more is that the body in the cpp file was generated by Visual Studio itself (i.e. the quick action menu in VS2015).

I'm no fan of 'help me understand this error' threads, but again, I'm pretty puzzled and I haven't been able to find information about this particular case. Feel free to point out my google skills as being atrocious though, a lmgfty won't hurt me.

It's also just possible that this simply isn't possible, but that seems odd to me, since using decltype on a regular member as trailing return type does work (be that an instance of a template class or not).

Advertisement
Can you post a minimal but complete example of this error? Context is important!

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

In the meantime this may be helpful. I replicated the errors you posted, but I've not got enough time to figure out how to clean them out at the moment.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Can you post a minimal but complete example of this error? Context is important!

Absolutely agree, so I've made my attempt at this, which (as it always does) gave me some direction by accident. As my project is somewhat out of date, it is/was still running on the VS2013 compiler. When creating a new project to create a min repro case, I didn't pay attention to this at first and blindly went in with using the VS2015 compiler. Funnily, this ran all fine, but when I noticed this and switched to the VS2013 compiler, the exact same errors popped up.

Without further ado, here's the repro case:

Header:


#pragma once
#include <vector>

class Test
{
    std::vector<int> m_Integers;

public:
    auto begin()->decltype(m_Integers.begin());
};

Cpp:


#include "Test.h"

int main()
{
}

auto Test::begin() -> decltype(m_Integers.begin())
{
    return m_Integers.begin();
}

Just for sake of completeness, I also tested this for several other functions (as you could consider begin and end special), such as back, but the errors were no different.

If anything, I dislike pointing at the compiler, but could this just be such an occasion? It seems extremely odd to me, considering the reproduction is so simple and doesn't seem that strange of a use case.

Edit: Alright I was testing out a bit more. I found the following to compile for neither VS2013 nor VS2015:

Header:


#pragma once
class Test
{
public:
    int foo();
    auto end()->decltype(foo());
};

Cpp:


#include "Test.h"

int main()
{
}

int Test::foo()
{
    return 0;
}

auto Test::end() -> decltype(foo())
{
    return foo();
}

Once again, this all does work if the implementation is given in the header, rather than the cpp. I can also not reproduce this at all when using decltype on a member variable instead. One more interesting case is where foo is static, in which case it also compiles. I feel like I'm doing something completely wrong in regard to member methods, but I can't find myself doing anything different from what I've seen others do (though I haven't spotted an occassion yet where a trailing return was used without it being a template class or method)

Out of curiosity, does the error still happen if you make m_Integers a public field?

That's a nope. Would have made things interesting, though, but see the added test which would make that a bit more unlikely.

What about if you use a type alias to work around it? Eg.:


class Test
{
public:
    int foo();
    using end_return_t = decltype(foo());
    auto end()-> end_return_t;
};

I tried your code under GCC 4.8.4 (with -std=c++11) and it compiled cleanly.

Stephen M. Webb
Professional Free Software Developer

Doing that for a member function is apparently not allowed in a static context, or more precisely as intelisense puts it, nonstatic member reference must be relative to a specific object. I'm not really sure why it seems to be confusing this for a method call, though. Attempting to hack around this using a pointer to the class itself and attempting a type alias as follows did not work either (left of ->foo must point to class/struct... etc.).


class Test
{
public:
    Test* test;

    int foo();
    using end_return_t = decltype(test->foo());

    auto end()->end_return_t;
};

Oh well, was worth a try, but I did manage to try this for the first test. Still does not manage to compile using VS2013, but it does produce 1 instead of 3 errors, namely:

'left of .begin must have class/struct/union'

Test is as follows:

Header:


#include <vector>

class Test
{
public:
    std::vector<int> m_Integers;

    using end_return_t = decltype(m_Integers.begin());

    auto end()->end_return_t;
};

Cpp:



#include "Test.h"

int main()
{
}

auto Test::end() -> end_return_t
{
    return end_return_t();
}

Edit:


I tried your code under GCC 4.8.4 (with -std=c++11) and it compiled cleanly.

Interesting. Did you happen to also test the latter case, where I reference a member function rather than indirectly referencing a member method on a member variable?

Would all these late hours of staring at code and slamming my head questioning why that damn thing wouldn't compile, have been because of the MSVC? If so, damn you Microsoft! :P

This topic is closed to new replies.

Advertisement