Why does if constexpr require an else to work?

  • A+
Category:Languages

I am trying to use if constexpr in the following way:

template<template <typename First, typename Second> class Trait,     typename First, typename Second, typename... Rest> constexpr bool binaryTraitAre_impl() {     if constexpr (sizeof... (Rest) == 0)     {         return Trait<First, Second>{}();         }     return Trait<First, Second>{}() and binaryTraitAre_impl<Trait, Rest...>(); } 

Example use case:

static_assert(binaryTraitAre_impl<std::is_convertible,     int, int&,     int*, void*>()); 

But this fails to compile

clang:

error: no matching function for call to 'binaryTraitAre_impl'         return Trait<First, Second>{}() and binaryTraitAre_impl<Trait, Rest...>();                                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

gcc:

prog.cc: In instantiation of 'constexpr bool binaryTraitAre_impl() [with Trait = std::is_convertible; First = int*; Second = void*; Rest = {}]': prog.cc:9:80:   required from 'constexpr bool binaryTraitAre_impl() [with Trait = std::is_convertible; First = int; Second = int&; Rest = {int*, void*}]' prog.cc:15:83:   required from here prog.cc:9:80: error: no matching function for call to 'binaryTraitAre_impl<template<class _From, class _To> struct std::is_convertible>()'     9 |         return Trait<First, Second>{}() and binaryTraitAre_impl<Trait, Rest...>();       |                                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~ prog.cc:3:17: note: candidate: 'template<template<class First, class Second> class Trait, class First, class Second, class ... Rest> constexpr bool binaryTraitAre_impl()'     3 |  constexpr bool binaryTraitAre_impl()       |                 ^~~~~~~~~~~~~~~~~~~ prog.cc:3:17: note:   template argument deduction/substitution failed: prog.cc:9:80: note:   couldn't deduce template parameter 'First'     9 |         return Trait<First, Second>{}() and binaryTraitAre_impl<Trait, Rest...>();       |                                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~ 

But I found the error goes away once I add else:

template<template <typename First, typename Second> class Trait,     typename First, typename Second, typename... Rest> constexpr bool binaryTraitAre_impl() {     if constexpr (sizeof... (Rest) == 0)     {         return Trait<First, Second>{}();     }     else     {         return Trait<First, Second>{}() and binaryTraitAre_impl<Trait, Rest...>();     } } 

live demo

What happened? Why can the compiler not infer the else in this case?

 


This is the excerpt from cppreference on constexpr if:

Constexpr If The statement that begins with if constexpr is known as the constexpr if statement.

In a constexpr if statement, the value of condition must be a contextually converted constant expression of type bool. If the value is true, then statement-false is discarded (if present), otherwise, statement-true is discarded.

It is clear that only one of the two branches is discarded. In your case, the culprit code cannot be discarded because it's outside the else clause.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: