1

The following code

#include <iostream>
#include <memory>
#include <ios>
using std::cout;
using std::endl;
using std::unique_ptr;
using std::make_unique;
using std::boolalpha;

template<typename T>
struct alloc{
    alloc();
    unique_ptr<T> operator() (void){
        return(auto up = make_unique<T>(NULL));
    }

};

int main (void){

    auto up = alloc<int>()();
    cout << boolalpha << ((up) ? 1 : 0) << endl; 
    return 0;
}

when compiled gives the following error:

g++ -ggdb -std=c++17 -Wall -Werror=pedantic -Wextra  -c code.cpp
code.cpp: In member function ‘std::unique_ptr<_Tp> alloc<T>::operator()()’:
code.cpp:14:16: error: expected primary-expression before ‘auto’
         return(auto up = make_unique<T>(NULL));
                ^~~~
code.cpp:14:16: error: expected ‘)’ before ‘auto’
make: *** [makefile:20: code.o] Error 1

There is an earlier question on SO reporting the same error:

C++17 std::optional error: expected primary-expression before 'auto'

The following is a snippet from the accepted answer to the above question:

Declarations are not expressions. There are places where expressions are allowed, but declararions are not.

So my questions based on the compilation error I get are:

a) Is the use of a declaration in a return statement not permitted by the standard?

b) What are the permitted contexts for declarations?

Note: I had deliberately used the auto keyword in the return statement to reproduce this error. This error had originally appeared in a larger code base.

TIA

Vinod
  • 925
  • 8
  • 9
  • 5
    What's the point of (trying to) declare a variable in a return statement? – 1201ProgramAlarm Aug 13 '19 at 04:48
  • There is not a single line of code which gives any sense to me. C sytle (void), make_unique with NULL. A useless constructor alloc, variable definition in return expression, ... – Klaus Aug 13 '19 at 06:35

1 Answers1

0

Is the use of a declaration in a return statement not permitted by the standard?

Indeed it isn't. We need only examine the grammar production at [stmt.jump]/1

Jump statements unconditionally transfer control.

jump-statement:
   break ;
   continue ;
   return expr-or-braced-init-listopt ;
   goto identifier ; 

There is no production that turns an "expr-or-braced-init-list" into any sort of statement, so no declaration statement either. There is also no production that turns it into any other sort of declaration (such as a function, namespace or class). So you cannot declare anything in the return statement's operand.

What are the permitted contexts for declarations?

Almost anywhere an expression isn't required explicitly. The very definition of a translation unit in C++ (one file being translated) is a sequence of declarations per [basic.link]/1.

A program consists of one or more translation units linked together. A translation unit consists of a sequence of declarations.

translation-unit:    
    declaration-seqopt

Different declarations have different structure. Somes such as namespaces, may contain more declarations. Others such as functions may contain statements, which themselves may be declaration statements of certain things. But most importantly, the standard makes clear where a statement may appear, and where only an expression is permitted.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458