2
votes

In trying to understand c++17 compliant code, i am confused by the following code in which the function uses the value from integral_constant type argument in the trailing return type. (please feel free to correct my terminolgy etc, trying to learn)

Two simple versions are illustrated below , with and without a decltype on the argument in the trailing return.

Using Compiler Explorer https://godbolt.org/z/vqmzhu

The first (bool_from1) compiles ok on
MSVC 15.8; /std:c++17, /O2, /permissive-
and clang 8.7.0.0 and gcc 8.2; -std=c++17, -O2, -pedantic
with correct assembler output

The second (bool_from2) errors out on gcc, It also shows Intellisense errors in VS but compiles without error.

I could not find anything in cppreference or standard draft, etc that would indicate to me that the decltype(atype) would be required for conforming code, however...???

My question would be is the decltype required. Are my compiler flags correct for c++17 conformance checking.

CODE:

#include <utility>

namespace ns {
volatile bool vb;

template<bool B> struct bool_ : std::bool_constant<B> {};

// using decltype(btype) in trailing return compiles in all 3
template<typename Bool> constexpr auto bool_from1(Bool btype)
-> bool_<decltype(btype)::value> {
    return bool_<btype.value>{};
}
void test1() {
    static_assert( // simple test
        bool_from1(std::true_type{}).value
        );
    vb = bool_from1(std::true_type{}).value; // check output
}

// without decltype in trailing return compile in VS and clang
// but errors out in gcc; and VS shows Intelisense errors but compiles
template<typename Bool>
constexpr auto bool_from2(Bool btype)
// ^ gcc 8.2 error: deduced class type 'bool_' in function return type
-> bool_<btype.value> {
    // ^ gcc: invalid template-id; use of paramter outside function body before '.'
    //^ VS Intellisense on btype: <error-constant>; a paramter is not allowed
    return bool_<btype.value>{};
}

void test2() {
    static_assert(
        bool_from2(std::true_type{}).value
        //^ gcc: bool_from1 was not declared in this scope
        );
    vb = bool_from2(std::true_type{}).value; // check output
}
}
1

1 Answers

1
votes

This looks like a gcc bug and bug report: "Trailing return types" with "non-type template arguments" which could be "constant expressions" produce a parsing error seems to fit this case:

Consider the following snippet:

template <int>
struct bar {};

template <class I>
auto foo(I i) -> bar<i()> { return {}; }

int main()
{
    foo([]{ return 1; }); // (0)
}

This compiles and works as intended on clang++5, but produces a compile-time error on g++7:

prog.cc:5:25: error: template argument 1 is invalid
auto foo(I i) -> bar<i()> { return {}; }