1

when I tried to reconstruct the SGI STL source code, I saw this code snippet

template <class _Func, class _Ret>
struct _STL_GENERATOR_ERROR {
  static _Ret __generator_requirement_violation(_Func& __f) {
    return __f();
  }
};
template <class _Func>
struct _STL_GENERATOR_ERROR<_Func, void> {
  static void __generator_requirement_violation(_Func& __f) {
    return __f();
  }
};

which was used to check the validity of the type of the relevant function signatures.

Here is my question: Why SGI intentionally specialized the case of void as return type ?

template <class _Func, class _Ret>
struct _STL_GENERATOR_ERROR {
  static _Ret __generator_requirement_violation (_Func& __f) {
    return __f();
  }
};

void hello() {}

int main(int argc, char const *argv[])
{
  void (*ptr)() = &hello;
  _STL_GENERATOR_ERROR<void(*)(), void>::__generator_requirement_violation(ptr);
  return 0;
}

My test code could normally pass the compiling (clang/llvm/x86_64), and normally run.

If I made mistake on either understanding the original code snipped or on the design of my test case, feel free to point it out!

Big thx.

Problem Solved, but FOLLOW UP: why my test case can handle the case of return void type?

Edee
  • 1,746
  • 2
  • 6
  • 14
  • Does the partial specialization you ask about actually use `return __f();` or `__f();`? It seems that `return __f();` would make the explicit partial specialization redundant to the generic implementation (they seem identical to me). – François Andrieux Oct 14 '20 at 14:10
  • @FrançoisAndrieux The source code use `return __f()` for the case of non-void-returning(__f() is non-void-returning), and simply invoke `__f()` for the case of void-returning, but what i am trying to figure out is, even I use `return __f()` for the case of void-returning, it still works very well. – Edee Oct 15 '20 at 09:24

1 Answers1

2

Even though returning a void expression from a void-returning function is legal C++ since ISO 981, we can imagine some early C++ compilers had not that feature implemented.

On such compiler, the generic template would cause an error for _Ret = void:

template <class _Func, class _Ret>
struct _STL_GENERATOR_ERROR {
  static _Ret __generator_requirement_violation(_Func& __f) {
    return __f();
  }
};

This is why we can guess a specialization was added (STL is old):

template <class _Func>
struct _STL_GENERATOR_ERROR<_Func, void> {
  static void __generator_requirement_violation(_Func& __f) {
    __f();
  }
};

1)

[stmt.return]/3

A return statement with an expression of type "cv-void" can be used only in functions with a return type-of-cv-void; the expression is evaluated just before the function returns to its caller.

source (p.98)

YSC
  • 38,212
  • 9
  • 96
  • 149
  • I didn't notice this was *actually* an STL question. There may also be a use case for the partial specialization to allow using the function with `_Ret` as `void` while `_Func` is a function type with a non-`void` return type. This way you could use a function with any return type when the return value is ignored. However, I'm not sure what the template is actually used for so this case may not actually be relevant. – François Andrieux Oct 14 '20 at 14:16
  • @FrançoisAndrieux You're right. That guess is worth an answer on its own. – YSC Oct 14 '20 at 14:17
  • OP's question shows the template specialization as returning with `return __f();`. This seems like an error to me, but if it is the case than my proposed use case would not work. I've left a comment hoping for clarification. – François Andrieux Oct 14 '20 at 14:18
  • @FrançoisAndrieux it's a typo if that [other source](http://labmaster.mi.infn.it/Laboratorio2/serale/www.sgi.com/tech/stl/concept_checks.h) is right. – YSC Oct 14 '20 at 14:22