void.pointer
void.pointer

Reputation: 26355

Confusion with auto assignment with list initialization syntax

I'm just now able to use C++11 for the first time at my job and I'm learning as I go. I have read GotW #94 and I'm trying to adopt his recommendation for using auto when declaring local variables instead of explicitly stating the type.

Given this, I have the following code:

class foo
{
};

int main()
{
    auto f = foo const*{nullptr};
}

My assignment in main does not compile and fails with:

main.cpp: In function 'int main()':
main.cpp:13:18: error: expected primary-expression before 'const'
     auto f = foo const*{nullptr};
                  ^

I feel like I'm missing something obvious. What am I doing wrong here?

(My sample is on coliru).

Upvotes: 3

Views: 127

Answers (2)

Praetorian
Praetorian

Reputation: 109119

When you use the functional notation for type conversion, the type name must be a simple-type-specifier or typename-specifier (§5.2.3 [expr.type.conv]), which basically means a type name consisting of a single word.

unsigned int a = unsigned int(42);

fails too, and there's no type inference or list initialization involved.

In my opinion, using auto in your example amounts to obfuscation. Just use

foo const* f{nullptr};

If you must use auto, create an alias

using foo_const_p = foo const*;
auto f = foo_const_p{nullptr};

Upvotes: 4

user743382
user743382

Reputation:

The T(x) and T{x} syntax don't allow arbitrary types to be used for T. Allowing it would make the syntax rather complicated in some cases. If you really want to use auto here, you'll need to wrap the type, like so:

template <typename T> using id = T;
auto f = id<foo const*>{nullptr};

but personally, I don't really think it's useful here.

To be more specific, the C++ syntax defines the grammatical constructs as

postfix-expression:
  ...
  simple-type-specifier ( expression-listopt )
  ...
  simple-type-specifier braced-init-list
  ...

simple-type-specifier:
  ::opt nested-name-specifieropt type-name
  ::opt nested-name-specifier template simple-template-id
  char
  char16_t
  char32_t
  wchar_t
  bool
  short
  int
  long
  signed
  unsigned
  float
  double
  void
  auto
  decltype-specifier

type-name:
  class-name
  enum-name
  typedef-name
  simple-template-id

The syntax to allow arbitrary types is part of the type-id rule, which is not one of the options of simple-type-specifier, but is one of the possibilities for the template-argument rule within a simple-template-id, which is why a template alias is a valid workaround.

Upvotes: 1

Related Questions