Search code examples
c++virtualconstexpr

Conflicting return type from constexpr virtual method?


I have the following code that won't compile. The compiler thinks that the return values differ which I fail to see.

Demo

#include <string_view>
#include <cstdio>

struct base
{
    virtual constexpr auto delimiter() const noexcept -> std::string_view = 0;
};

struct derived : public base
{
    constexpr auto delimiter() const noexcept override -> std::string_view { return "/"; }
};

int main() { }

Idk if I have maybe placed my keywords in the wrong order. It does compile without the override keyword.

Error:

<source>:11:47: error: expected ';' at end of member declaration
   11 |     constexpr auto delimiter() const noexcept override -> std::string_view { return "/"; }
      |                                               ^~~~~~~~
      |                                                       ;
<source>:11:56: error: expected unqualified-id before '->' token
   11 |     constexpr auto delimiter() const noexcept override -> std::string_view { return "/"; }
      |                                                        ^~
<source>:11:20: error: conflicting return type specified for 'virtual constexpr auto derived::delimiter() const'
   11 |     constexpr auto delimiter() const noexcept override -> std::string_view { return "/"; }
      |                    ^~~~~~~~~
<source>:6:28: note: overridden function is 'virtual constexpr std::string_view base::delimiter() const'
    6 |     virtual constexpr auto delimiter() const noexcept -> std::string_view = 0;
      |   

Solution

  • I have maybe placed my keywords in the wrong order

    Yes, that's your problem. Put the override token after the trailing return type:

    struct derived : public base {
        auto constexpr delimiter() const noexcept -> std::string_view override { return "/"; }
    };
    

    This is because the -> std::string_view is part of the function declarator and the override specifier must be placed immediately after that declarator (and just before the function body, if present).

    More details on cppreference, and see here for more on "function declarators".

    In terms of the C++ Standard, override is one of the two "virtual specifiers" (along with final); the best citation I can make from this Draft C++17 Standard is from "Appendix A - Grammar Summary", where a function definition is described in the following terms:

    A.7 Declarators          [gram.decl]


    function-definition:
         attribute-specifier-seqopt decl-specifier-seqopt declarator virt-specifier-seqopt function-body
         attribute-specifier-seqopt decl-specifier-seqopt declarator requires-clause function-body

    This makes it clear that the virt-specifier-seq (one or more of virtual and final) is not part of the declarator and should be between that and the function body. In this 'latest' online Draft Standard, the relevant section is much the same, with the added benefit of links in the various parts of the function definition.