Best way to trigger a compile-time error if no if-constexpr's succeed?

Viewed 221

I have a long series of if constexpr statements and would like to trigger a compile-time error if none of them succeed.

Specifically, I have an abstract syntax tree whose result I would like to convert to a specific set of types that I might need. I have AsInt(), AsDouble(), etc. working, but I need to be able to do so more dynamically based on a supplied type.

As things stand, I've written a templated As() member function, but it's error-checking is clunky. Specifically, using static assert requires an unwieldy test condition. Here's a simplified version:

template <typename T>
T As() {
  if constexpr (std::is_same_v<T,int>) return AsInt();
  if constexpr (std::is_same_v<T,double>) return AsDouble();
  ...
  if constexpr (std::is_same_v<T,std::string>) return AsString();

  static_assert( std::is_same_v<T,int>
                 || std::is_same_v<T,double>
                 || ...
                 || std::is_same_v<T,std::string>,
                 "Invalid template type for As()" );
}

Is there a simpler way to trigger the static assert (or equivalent) if all of the conditions fail?

1 Answers

You need to rewrite your sequence of if constexprs as a chain of if constexpr ... else if constexpr ... and have the final else clause trigger a compilation error if "reached" (i.e., not discarded). This can be done using the "dependent false idiom":

if constexpr (std::is_same_v<T,int>) {
    return AsInt();
} else if constexpr (std::is_same_v<T,double>) {
    return AsDouble();
} ... else if constexpr (std::is_same_v<T,std::string>) {
    return AsString();
} else {
    // this is still constexpr, so it will be discarded if any other branch was taken
    static_assert(dependent_false<T>::value, "invalid template type for As()");
}

where dependent_false is defined as:

template <class T> struct dependent_false : std::false_type {};
Related