-1

I develop a cross-platform (Linux and Win) library. Within it I use of following helper templated functions to work with tuples (as example):

#include <iostream>
#include <string>
#include <tuple>
#include <utility>
#include <type_traits>

using namespace std;

template <class F, size_t... Is>
constexpr void index_apply_impl1(const F &f,
                                const index_sequence<Is...>&) {
    int d[] = { 0, (f(integral_constant<size_t, Is> {}), 0)... };
}

template <size_t N, class F>
constexpr void index_apply1(const F& f) {
    index_apply_impl1(f, make_index_sequence<N>{});
}

template <class Tuple, class F>
constexpr void apply1(const Tuple &t, const F &f) {
    index_apply1<tuple_size<Tuple>{}>(
        [&](auto &Is) { f(get<Is>(t)); } );
}

template <size_t N, class F>
constexpr void apply_by_index1(const F &f) {
    index_apply1<N>(
        [&](auto &&Is) { f(integral_constant<size_t, Is> {}); });
}

int main() {
    auto t = make_tuple("aaa", 1, 11.11);

    // does not work with gcc too
    //apply1(t, [&](auto &v) { cout << v << endl;} );

    apply_by_index1<tuple_size<decltype(t)>::value>([&](auto &&i) { cout << get<i>(t) << endl; });
}

This code is successfully compiled and works as expected with GCC 5.4 and 6.4, but it won't be compiled with MS Build tools 2015 (MS VC++ 2017 version is not checked yet). The error VC++ compiler prints is related to "auto"-type argument "Is" of the lambdas in the function "apply_by_index1". VC++ says:

zz.cpp(29): error C2975: '_Val': invalid template argument for 'std::integral_constant', expected compile-time constant expression

...

zz.cpp(38): error C2672: 'get': no matching overloaded function found zz.cpp(29): note: see reference to function template instantiation 'auto main::::operator ()>(std::integral_constant &&) const' being compiled

zz.cpp(38): error C2975: '_Idx': invalid template argument for 'std::get', expected compile-time constant expression

... and so on

Is it generaly possible to implement such a functions with VC++ or did I miss something? My thoughts are replacing lambdas with functors but still I have not idea how to implement it (i'm not a proffesional programmer)

I have no Clang/llvm but I belive this code should be compiled by Clang of version >=4. Right?

Timur
  • 21
  • 3
  • _sorry I have no Windows-machine now and cannot reproduce the error exactl_ sorry, I will not do. your work. –  Sep 12 '17 at 10:21
  • I'm curious how you managed to get gcc 5.4 to even accept this. [I wasn't able to](https://godbolt.org/g/t5Um7M). And fwiw, [clang 4.01 won't take it either](https://godbolt.org/g/ESbypC). – WhozCraig Sep 12 '17 at 10:24
  • WhozCraig, sorry, my mistake! apply1 does not realy work, but apply_by_index1 works with gcc 5.4. – Timur Sep 12 '17 at 10:50
  • Have you checked [`std::apply`](http://en.cppreference.com/w/cpp/utility/apply) or [this](https://stackoverflow.com/a/20441189/1023390) C++14 implementation? – Walter Sep 12 '17 at 10:51

1 Answers1

0

I can give you at least a partial solution. You still cannot use std::get inside the lambda.

namespace detail
{
    template <typename T, typename F, typename... Ts, size_t... Is>
    void apply1(T&& t, F&& f, std::index_sequence<Is...>)
    {
        const int d[] = { 0, (f(std::get<Is>(t)), 0)... };
    }
    template <typename T, typename F, size_t... Is>
    void apply_by_index1(T&& t, F&& f, std::index_sequence<Is...>)
    {
        const int d[] = { 0, (f(Is), 0)... };
    }

    template <size_t I, typename... Ts>
    constexpr auto create_element(Ts&&... ts)
    {
        return std::make_tuple(std::get<I>(std::forward<Ts>(ts))...);
    }

    template <typename... Ts, size_t... Is>
    constexpr auto merge(std::index_sequence<Is...>, Ts&&... ts)
    {
        return std::make_tuple(create_element<Is>(std::forward<Ts>(ts)...)...);
    }
}

template <typename T, typename F>
void apply1(T&& t, F&& f)
{
    detail::apply1(std::forward<T>(t), std::forward<F>(f), std::make_index_sequence<std::tuple_size<std::decay_t<T>>::value>());
}

template <typename T, typename F>
void apply_by_index1(T&& t, F&& f)
{
    detail::apply_by_index1(std::forward<T>(t), std::forward<F>(f), std::make_index_sequence<std::tuple_size<std::decay_t<T>>::value>());
}

template <typename T, typename... Ts>
constexpr auto merge(T&& t, Ts&&... ts)
{
    return detail::merge(std::make_index_sequence<std::tuple_size<std::decay_t<T>>::value>(), std::forward<T>(t), std::forward<Ts>(ts)...);
}

int main() {
    const auto t1 = std::make_tuple("Hallo ", "Hallo ", "Hallo ");
    const auto t2 = std::make_tuple("World", "Jon", "Peter");
    const auto t3 = std::make_tuple("!", "!", "!");
    const auto t4 = merge(t1, t2, t3);

    apply1(t4, [](const auto& e)
    {
        std::cout << std::get<0>(e) << std::get<1>(e) << std::get<2>(e) << std::endl;
    });

    return 0;
}
Martin Fehrs
  • 792
  • 4
  • 13