c++language-lawyerc++17if-constexprtemplate-instantiation

Does "if constexpr(something false)" ALWAYS omit template instantiation


Will this template function f<X>() be always NOT instantiated?

if constexpr(something false){
     //some template function OR function in template class
     f<X>();
}

Below is my test (coliru MCVE).
I created fun<S>() that will instantiate E<S> if and only if S!=void.
Then I call fun<void>(),fun<int>() and fun<float>().

I believe if constexpr(false) forces C++ compiler to skip the #1 part for fun<void>().
My countRunner should be ++ only 2 times.

Thus, if my assumption is true, the below program will always prints 2 in every compiler and every setting.

(It printed 2 for me, but the experiment alone proves nothing.)

#include<iostream>
int countRunner=0;
template<class T> class E{
    public: static int countIndex;
    public: E(){
        if(false){
            int unused=E::countIndex;
        }
    }
};
template<class T> int E<T>::countIndex=countRunner++;
template<class S> void fun(){
    if constexpr(!std::is_same_v<void,S>){
        E<S> e;  //#1  - S=int,float, but never void
    }
}
int main (){
    fun<void>();
    fun<int>();
    std::cout<<"testResult="<<countRunner<<std::endl;
    fun<float>();
}

Can I rely that E<void> will never be instantiated?
Please provide some (semi-)official reference to make me calm down.

Edit: I just found http://eel.is/c++draft/stmt.if#2 and "If constexpr" in C++17 does not work in a non-templated function.

If the if statement is of the form if constexpr, the value of the condition shall be a contextually converted constant expression of type bool; this form is called a constexpr if statement. If the value of the converted condition is false, the first substatement is a discarded statement, otherwise the second substatement, if present, is a discarded statement. During the instantiation of an enclosing templated entity, if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not instantiated. [ Note: Odr-uses in a discarded statement do not require an entity to be defined. — end note  ] A case or default label appearing within such an if statement shall be associated with a switch statement within the same if statement. A label declared in a substatement of a constexpr if statement shall only be referred to by a statement in the same substatement.

I am still not sure about the word "instantiated" in the rule. Does it have the same meaning as in "template instantiation"?


Solution

  • Does it have the same meaning as in "template instantiation"?

    Yes, it does. The specification speaks of "discarded" statements, and has meaning only in the context of template instantiation for some enclosing templated entity.

    [stmt.if] (emphasis mine)

    2 If the if statement is of the form if constexpr, the value of the condition shall be a contextually converted constant expression of type bool; this form is called a constexpr if statement. If the value of the converted condition is false, the first substatement is a discarded statement, otherwise the second substatement, if present, is a discarded statement. During the instantation of an enclosing templated entity, if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not instantiated.

    The important bit is the condition being value-dependent after the parameters are substituted. On one leg, it means that if the condition depends only on the parameters of the immediately enclosing template that is being instantaited, it will not be part of the instantiation of that template.

    In your case, it means exactly that if std::is_same_v<void,S> is true, the body of the "if" won't be part of the instantiated fun<void>.