0

I'm having trouble expanding an array reference. When I pass the array reference to a function template as an argument, the constant nature of the array reference seems to be lost:

#include <cstdlib>
#include <utility>

template<const char ... C>
struct hint_for_opt_cls_holder {
    constexpr static const char value[] { '?', C... };
};
template<size_t N, size_t... Is>
static constexpr auto
create_hint_for_opt_cls(const char (&cname)[N],
                        std::index_sequence<Is...>) {
    // fails: cname is not a constant expression
    return hint_for_opt_cls_holder<cname[Is]...>::value;
}
template<size_t N>
static constexpr auto
create_hint_for_opt_cls(const char (&cname)[N]) {
    constexpr decltype(auto) cname_ = cname; // fails already here, actually
    return create_hint_for_opt_cls(cname,
                                    std::make_index_sequence<N>());
}

constexpr static char name[] = "foobar";
constexpr static auto& get_class_name() {
    return name;
}
int main() {
    // works! knows the return is constant
    constexpr decltype(auto) cname = get_class_name();
    auto x = create_hint_for_opt_cls(cname);
}
Artefacto
  • 96,375
  • 17
  • 202
  • 225
  • You only need `constexpr` for things that are *expressions*. For stuff like `"foobar"` you can just `const ...`. – tadman Nov 21 '20 at 03:22

1 Answers1

1

Arguments are not constexpr, you have to turn them in type:

gcc/clang have an extension to allow to build UDL from literal string:

// That template uses the extension
template<typename Char, Char... Cs>
constexpr auto operator"" _cs() -> std::integer_sequence<Char, Cs...> {
    return {};
}

See my answer from String-interning at compiletime for profiling to have MAKE_STRING macro if you cannot used the extension (Really more verbose, and hard coded limit for accepted string length).

Then

template<char ... Cs>
static constexpr auto
create_hint_for_opt_cls(std::integer_sequence<char, Cs...>) {
    return hint_for_opt_cls_holder<Cs...>::value;
}

constexpr static auto name = "foobar"_cs;
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Thanks for your answer. Couple of followups: 1) In your other answer you have this definition: `template constexpr char at(const char (&a)[N]) { return I < N ? a[I] : '\0'; }`. Why would that work, but not my `create_hint_for_opt_cls`? 2) is this something special about an array reference? If I was passing an `std::array` would that make any difference? – Artefacto Nov 21 '20 at 16:04
  • You cannot use parameter as constexpr inside the function itself, but constexpr result might depend of input. Nothing special about array reference, `std::array` or any literalType. – Jarod42 Nov 21 '20 at 18:21