9
votes

I encountered this "beautiful" example of "highly readable" and "elegant" code, but I'm having troubles understanding it:

struct S {

    [[noreturn]] virtual inline auto f(const unsigned long int *const)
                         –> void const noexcept;
};

Here's what I understand (please correct me if I'm wrong):

  • f() is a member function of S
  • virtual - can be overridden by derived classes
  • inline - compiler should attempt to generate code for a call to f rather than calling it normally
  • const - the function is not able to change any of S's members
  • noexcept - the function will never throw (cannot throw or not allowed to throw)
  • parameter: a const pointer to a const unsigned long int
  • auto .... -> void - suffix return type void
  • [[noreturn]] - it never returns

Here are my main concerns:

  • If a function is declared as [[noreturn]], it never returns to its caller; so how can it have a return type void? What is the point of a return type in this function anyway?
  • Would this code compile with int instead of void for example?
  • What would be a practical use for a function like that? To throw an exception?
  • Where does the flow of the code go after this function finishes executing (after } )?

I couldn't get this code to run on VS2013 Preview, so I guess these features weren't implemented yet.

I'm very curious about this, so I'll appreciate it if someone can explain! Cheers

4
@TemplateRex Actually it's not a duplicate because I asked 4 questions in the end that need more information than what was answered in that postOleksiy
well those other questions are insufficiently supported with code, i.e. an SSCCE, and what-did-you-try?TemplateRex
@TemplateRex I can't try anything because my compiler does not even understand what [[noreturn]] means. I need help, that's why I'm asking.Oleksiy
there are plenty of online compilers that support it, you should really put in more effort in narrowing your question, for others to be able to help youTemplateRex
While the first of the four questions is answered in the question marked as duplicate, the other three are not, and they are valid questions. So maybe remove that first question. You have my vote for reopening. @TemplateRex there is nothing to narrow in the third and fourth question, and if you read the second as "does the standard allow...", there is no narrowing for the second either.Arne Mertz

4 Answers

19
votes

The [[noreturn]] is an attribute which has whatever semantics it has. It doesn't change, however, how the function is declared: all normal functions in C++ (i.e., all functions except the constructors, destructors, and conversion operators) have a declared return type. Adding any attribute doesn't change this rule.

The purpose of the [[noreturn]] attribute is probably to indicate that the function never returns in a normal way. Given that the function is also declared to be noexcept it basically means that the corresponding function also can't thrown an exception. One example of a function with similar behavior is exit() which terminates the program. I could imagine that functions implementing some sort of application-loop could also qualify. In any case, the [[noreturn]] tells the system that the corresponding function will never normally return, i.e., falling off the function ("after }") will probably result in undefined behavior.

6
votes

If a function is declared as [[noreturn]], it never returns to its caller; so how can it have a return type void? What is the point of a return type in this function anyway?

From this Q&A you can see that noreturn is a way to tell the compiler that a function does not return. Normally this means it either has an infinite loop (often seen in servers that are supposed to run indefinitely) or it calls exit(), terminate() and the like, exiting the application without returning to main.
[[noreturn]] is optional, i.e. you don't have to specify it. It's an attribute, i.e. the basic syntax of defining/declaring the function remains untouched, so the function has to have a return type as any other function has.

Would this code compile with int instead of void for example?

Yes, it would, although the compiler might warn you that it does not make sense having something returned from a function that never returns.

What would be a practical use for a function like that? To throw an exception?

The first thing that comes to mind is some endless loop, e.g. handling incoming requests at a server. Throwing an exception is ok for [[noreturn]] functions as well, but its not really an option here, because it explicitly says noexcept. Throwing would trigger a call to std::terminate(), leading to program termination itself but previosuly to an implementation defined amount of stack unwinding, wich in fact means [[noreturn]] would still be applicable.

Where does the flow of the code go after this function finishes executing (after } )?

The function never reaches its closing }. It either runs endlessly (until someone pulls the plug), or it exits abnormally, i.e. by program termination. In other words, if the function does not execute any more, it has not really finished but aborted execution, and there is no program and no control flow to go to.

2
votes

The other answers are great, but I'm going to present an alternative answer for

If a function is declared as [[noreturn]], it never returns to its caller; so how can it have a return type void? What is the point of a return type in this function anyway?

One reason why you might need a return type (and a non-void return type at that) is if the function is overriding a super classes method.

struct Parent {
   virtual int f()=0;
}

struct Child {
    [[noreturn]] override int f() noexcept { ... }
};

In some contexts the compiler will be able to use the [[noreturn]] to produce better code. But in other situations f might be called polymorhically, and thus needs to conform to its parents signature.

0
votes

If a function is declared as [[noreturn]], it never returns to its caller; so how can it have a return type void? What is the point of a return type in this function anyway?

I have found one practical example of a non-void [[noreturn]] function. It is in a case, when used in ?: operator to provide a correct result type of ?: operator:

template <class T> [[noreturn]] T fail(char const *s) noexcept { puts(s); exit(1); }
enum E { V1, V2 };
int f(E e) {
  return (e == V1) ? 1 : (e == V2) ? 2 : fail<E>("bad e");
}

Note: One could have a feeling that [[noreturn]] functions in ?: operator could be ignored for calculation of ?: result type. But it is not possible because [[noreturn]] is not a part of result type of an expression (fail<T>("") has result type T and not [[noreturn]] T).

What would be a practical use for a function like that? To throw an exception?

See the example of such function fail above.