2

I'm trying to create a function foobar() that can be used as...

int main()
{
    auto x = foobar(__func__);
    // decltype(x) = std::integer_sequence<char, 'm', 'a', 'i', 'n'>
}

Any hints?

The code does not need to work on MSVC.

vinipsmaker
  • 2,215
  • 2
  • 19
  • 33
  • C++ has very limited introspection capabilities. You're going to have to wait if this is exactly what you want. – chris Sep 29 '20 at 20:05
  • 1
    The "macro" `__func__` already expands to a `constexpr` `"main"`. This isn't an introspection problem. – vinipsmaker Sep 29 '20 at 20:09
  • C++11, C++14, C++17 or C++20? – max66 Sep 29 '20 at 20:19
  • 2
    @max66 At least 14, given `integer_sequence`. – cigien Sep 29 '20 at 20:20
  • @cigien - Good point. – max66 Sep 29 '20 at 20:21
  • @vinipsmaker, Fair enough. I guess what I was getting at is that you receive the array as a plain array. If you want to turn its contents into template arguments, you have to fit it into template-land from the get-go. Once you pass it as a regular parameter, it's already too late because parameters are not constant expressions. And then you have to deal with passing the local array as a template argument. Where I was going is that `foobar(reflexpr(main))` is an incredibly more doable process. – chris Sep 29 '20 at 21:08
  • @Evg, What you're seeing is `__func__` passed to the macro and used in the context of the closure's `operator()`. `__func__` is a compile-time array rather than a preprocessor-time string literal. – chris Sep 29 '20 at 21:17
  • @chris, got it, thanks. – Evg Sep 29 '20 at 21:43
  • 1
    [This](https://stackoverflow.com/a/31074039/8372853) appears to be a good option. – cigien Sep 30 '20 at 00:48
  • 1
    @cigien, thanks for the hint. It's working for me. – vinipsmaker Sep 30 '20 at 04:28

2 Answers2

4

The problem I see is that passing __func__ as a function argument

foobar(__func__);

I don't see a way to change the returned type of foobar() according the value of __func__.

Different if you pass __func__ as template parameter, but __func__ is a string literal, and a string literal (as far I know) can't be a template parameter before C++20.

But... if you accept a C++20 solution where __func__ is passed as template parameter... I suppose you can write something as follows

#include <utility>
#include <array>

template <std::size_t N>
struct bar
 {
   using index_type = std::make_index_sequence<N-1u>;
    
   std::array<char, N-1u> arr;
    
   template <std::size_t ... Is>
   constexpr bar (std::index_sequence<Is...>, char const (&a0)[N]) : arr{a0[Is]...}
    { }
    
   constexpr bar (char const (&a0)[N]) : bar{index_type{}, a0}
    { }
 };

template <bar b, std::size_t ... Is>
constexpr auto baz (std::index_sequence<Is...>)
 -> std::integer_sequence<char, b.arr[Is]...>
 { return {}; }

template <bar b>
constexpr auto foo () 
 { return baz<b>(typename decltype(b)::index_type{}); }

int main ()
{
  using target_type = std::integer_sequence<char, 'm', 'a', 'i', 'n'>;
    
  constexpr auto x = foo<__func__>();
    
  static_assert( std::is_same_v<decltype(x), target_type const> );
}
max66
  • 65,235
  • 10
  • 71
  • 111
1

Here is the approach that works with GCC and Clang without need for C++20 using the statement expression language extension:

template<std::size_t n>
struct helper {
    const char(& s)[n];
    
    constexpr helper(const char(& str)[n]) : s(str)
    {}
    
    template<class Fn, std::size_t... is>
    static constexpr auto apply(Fn fn, std::index_sequence<is...>) {
        return fn(std::integral_constant<std::size_t, is>{}...);
    }

    template<class Fn>
    static constexpr auto apply(Fn fn) {
        return apply(fn, std::make_index_sequence<n - 1>{});
    }
};


#define arr_as_char_sequence(ARR)                                         \
    ({ constexpr helper my_helper(ARR); my_helper.apply([](auto... is)    \
          { return std::integer_sequence<char, my_helper.s[is]...>{}; }); });

void foo() {
    auto name = arr_as_char_sequence(__func__);
    static_assert(std::is_same_v<
        decltype(name), std::integer_sequence<char, 'f', 'o', 'o'>>);
}

Demo

Evg
  • 25,259
  • 5
  • 41
  • 83