Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

template signature resolving to void(void) rejected by gcc; is this valid C++?

Tags:

c++

I think this code is valid C++. MSVC agrees but gcc seems to disagree. Are MSVC and I wrong? (Or should I be typing something slightly different?)

#include <iostream>
#include <string>
#include <vector>

#include <functional>

template <typename T>
struct S
{
  template <typename R>
  void f(std::function<R(T)> fn)
  {
    auto p = &fn;
    ++p;
  }
  template <typename R>
  void g(std::function<R(void)> fn)
  {
    auto p = &fn;
    ++p;
  }
};

void f()
{
  S<void> s;
  auto p = &s;
  ++p;
}

int main()
{
    f();
}

error message:

<source>: In instantiation of 'struct S<void>':

<source>:26:11:   required from here

<source>:11:8: error: invalid parameter type 'void'

   void f(std::function<R(T)> fn)

        ^

<source>:11:8: error: in declaration 'void S<T>::f(std::function<R(T)>)'

Compiler returned: 1

gcc seems to be fine if I write the literal, void, as the parameter type (see parameter to function g()). But it is unhappy if I write T and then resolve T to void (see parameter to function f()).

like image 476
B Simpson Avatar asked Oct 16 '18 00:10

B Simpson


1 Answers

No, your example is not valid C++. The rule that allows (void) to be a function parameter list with no parameters is found in Standard section [dcl.fct], paragraph 4:

A parameter list consisting of a single unnamed parameter of non-dependent type void is equivalent to an empty parameter list. Except for this special case, a parameter shall not have type cv void.

The key for your question is the word "non-dependent", meaning not depending on a template parameter. The requirement was probably written this way because it would be too surprising to write the function declaration void func(T); within a template, expecting it to always be a function type taking exactly one parameter, and then find in one case it might not be.

So:

void f1(void);           // okay - classic style from C

void f2(void nothing);   // error - the phony "void" parameter cannot be named

void f3(const void);     // error - const void is a different type

using VoidType = void;
void f4(VoidType);       // okay - using a non-dependent type alias

template <typename T>
void f5(T);
void (*fptr)(void) = f5<void>; // error - dependent parameter type cannot be void
like image 94
aschepler Avatar answered Oct 31 '22 22:10

aschepler