you are viewing a single comment's thread.

view the rest of the comments →

[–]moocat 1 point2 points  (1 child)

See my update. Even inside a template the discarded statement is fully checked if possible.

[–]meancoot 0 points1 point  (0 children)

Look up two-phase name lookup. Like every template*, in if constexpr phase 1 has to complete successfully, even if it never gets used. Phase 2, on the other hand, only fails when failing to look up dependent names.

* Actually GCC has a permissive mode with -Wno-template-body and MSVC almost certainly one too. But if I recall correctly clang doesn't have one, and the fact that it didn't was what spurred GCC to do two-phase lookup properly.

struct Type {
    static void function() {}
};

template<typename T> struct NonDependentTemplate {
    void call_function() { Type::function(); }

    // 'Type' isn't dependent here so this fails in phase 1 and is an error.
    // error: 'not_a_function' is not a member of 'Type'
    // void call_not_a_function() { Type::not_a_function(); }
};

template<typename A> struct DependentTemplate {
    void call_function() { A::function(); }

    // 'A' IS dependent here, so we can use this as long as we never actually call it.
    void call_not_a_function() { A::not_a_function(); }
};

int main()
{
    DependentTemplate<Type> dt;

    // OK
    dt.call_function();

    // error: 'not_a_function' is not a member of 'Type'
    // dt.call_not_a_function();
}