Is it valid to do explicit template specialisation with auto return 'type' in C++14?
Asked Answered
O

1

5

Previous question.

I repeat the code from the previous question to make this question self-contained. The code below compiles and does not issue any warnings if it is compiled using gcc 4.8.3. with -std=c++1y. However, it does issue warnings if compiled with -std=c++0x flag. In the context of the previous question it was stated that the code does not compile using gcc 4.9.0. Unfortunately, at present, I do not fully understand how auto is implemented. Thus, I would appreciate if anyone could answer the following questions:

1). Is the code below valid C++ with respect to the C++14 standard?

2). If yes, would this code be considered a good style? If not, why not?

3). Why does the code below compile and work (sometimes) when using C++11 compilers? Alternatively, why does it not always work? Are there any specific flags/options/settings that could prevent it from working?

template<int N> auto getOutputPort2();
template<> auto getOutputPort2<0>();
template<> auto getOutputPort2<1>();

template<>
auto getOutputPort2<0>()
{
    return std::unique_ptr<int>(new int(10));
}

template<>
auto getOutputPort2<1>()
{
    return std::unique_ptr<string>(new string("qwerty"));
}
Otho answered 24/12, 2014 at 0:6 Comment(5)
See [dcl.spec.auto]/13 "Redeclarations or specializations of a function or function template with a declared return type that uses a placeholder type shall also use that placeholder, not a deduced type."Sightly
The use of auto seems fine to me. The use of an int value to switch on different meanings of the same function looks suspect.Prichard
"If yes, would this code be considered a good style? If not, why not?" For this part of the question, I'd suggest you ask on CodeReview.SESightly
What does "work (sometimes)" mean?Droplet
@Droplet I am afraid this was a reference to my previous question (see one of the links in the beginning of this question). When using c++11, the code does not compile with gcc 4.9, but compiles (with a warning) and runs as expected with gcc 4.8.3.Otho
S
7

1). Is the code below valid C++ with respect to the C++14 standard?

Yes, as far as I can tell. It's sometimes a bit hard to prove, since often there's simply nothing forbidding it. However, we can look at an example in a recent draft (post-N4296), [dcl.spec.auto]/13:

template <typename T> auto g(T t) { return t; } // #1
template auto g(int);                           // OK, return type is int
template char g(char);                          // error, no matching template
template<> auto g(double);                      // OK, forward declaration with
                                                // unknown return type

The same paragraph specifies:

Redeclarations or specializations of a function or function template with a declared return type that uses a placeholder type shall also use that placeholder, not a deduced type.

So the explicit specializations of a function template must use return type deduction. I cannot find anything that forbids different return types for different specializations. Similarly, in C++98, different return types for function template specializations (of the same primary template) can be achieved by making the return type dependent on the template arguments. By using metaprogramming, you can basically achieve the same as when using return type deduction to specify unrelated return types for the different specializations.


3). Why does the code below seem to compile and work (sometimes) using C++11 compilers?

The code in the OP is ill-formed in C++11. Return type deduction for ordinary functions (non-lamdas) is a feature introduced in C++14. A program that contains this code snippet is ill-formed. However, the Standard does not mandate that implementations (compilers) must reject ill-formed programs. It merely states in [intro.compliance]/2.2:

If a program contains a violation of any diagnosable rule [...] a conforming implementation shall issue at least one diagnostic message.

and in /8

A conforming implementation may have extensions (including additional library functions), provided they do not alter the behavior of any well-formed program. Implementations are required to diagnose programs that use such extensions that are ill-formed according to this International Standard. Having done so, however, they can compile and execute such programs.

(So implementations can accept this program as an extension.)

g++4.8.3 issues a warning, which counts as a diagnostic message. g++4.9 issues an error, which is also a diagnostic message. Both are compliant. By specifying -Werror, you could tell a g++4.8.3 to reject this program. (You'd have to ask the gcc developers why they've changed that from a warning to an error.)

Sightly answered 24/12, 2014 at 1:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.