Get first element of std::tuple satisfying trait











up vote
2
down vote

favorite












I'm using C++17. I'd like to get an element of a tuple that satisfies some type trait. It would be amazing if the trait could be supplied generically, but I'd be satisfied with a specific function for a certain trait. Usage might look something like this:



auto my_tuple = std::make_tuple { 0.f, 1 };

auto basic = get_if_integral (my_tuple);
auto fancy = get_if<std::is_floating_point> (my_tuple);

std::cout << basic; // '1'
std::cout << fancy; // '0.f'


Ideally this would fail to compile if more than one element satisfies the trait, like std::get (std::tuple).










share|improve this question
























  • For me it is unclear what your question is. What is wrong with std::get_if<float>(my_tuple)?
    – mkaes
    Nov 11 at 16:20










  • That would be just std::get<float> (my_tuple), I think. The context I'm using it is a little more complex, this is just an example. I have a tuple of tuples, and I want to return a reference to the first inner tuple that satisfies some trait.
    – tommaisey
    Nov 11 at 16:23

















up vote
2
down vote

favorite












I'm using C++17. I'd like to get an element of a tuple that satisfies some type trait. It would be amazing if the trait could be supplied generically, but I'd be satisfied with a specific function for a certain trait. Usage might look something like this:



auto my_tuple = std::make_tuple { 0.f, 1 };

auto basic = get_if_integral (my_tuple);
auto fancy = get_if<std::is_floating_point> (my_tuple);

std::cout << basic; // '1'
std::cout << fancy; // '0.f'


Ideally this would fail to compile if more than one element satisfies the trait, like std::get (std::tuple).










share|improve this question
























  • For me it is unclear what your question is. What is wrong with std::get_if<float>(my_tuple)?
    – mkaes
    Nov 11 at 16:20










  • That would be just std::get<float> (my_tuple), I think. The context I'm using it is a little more complex, this is just an example. I have a tuple of tuples, and I want to return a reference to the first inner tuple that satisfies some trait.
    – tommaisey
    Nov 11 at 16:23















up vote
2
down vote

favorite









up vote
2
down vote

favorite











I'm using C++17. I'd like to get an element of a tuple that satisfies some type trait. It would be amazing if the trait could be supplied generically, but I'd be satisfied with a specific function for a certain trait. Usage might look something like this:



auto my_tuple = std::make_tuple { 0.f, 1 };

auto basic = get_if_integral (my_tuple);
auto fancy = get_if<std::is_floating_point> (my_tuple);

std::cout << basic; // '1'
std::cout << fancy; // '0.f'


Ideally this would fail to compile if more than one element satisfies the trait, like std::get (std::tuple).










share|improve this question















I'm using C++17. I'd like to get an element of a tuple that satisfies some type trait. It would be amazing if the trait could be supplied generically, but I'd be satisfied with a specific function for a certain trait. Usage might look something like this:



auto my_tuple = std::make_tuple { 0.f, 1 };

auto basic = get_if_integral (my_tuple);
auto fancy = get_if<std::is_floating_point> (my_tuple);

std::cout << basic; // '1'
std::cout << fancy; // '0.f'


Ideally this would fail to compile if more than one element satisfies the trait, like std::get (std::tuple).







c++ c++17 variadic-templates template-meta-programming stdtuple






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 11 at 19:58









max66

33.8k63762




33.8k63762










asked Nov 11 at 16:02









tommaisey

1317




1317












  • For me it is unclear what your question is. What is wrong with std::get_if<float>(my_tuple)?
    – mkaes
    Nov 11 at 16:20










  • That would be just std::get<float> (my_tuple), I think. The context I'm using it is a little more complex, this is just an example. I have a tuple of tuples, and I want to return a reference to the first inner tuple that satisfies some trait.
    – tommaisey
    Nov 11 at 16:23




















  • For me it is unclear what your question is. What is wrong with std::get_if<float>(my_tuple)?
    – mkaes
    Nov 11 at 16:20










  • That would be just std::get<float> (my_tuple), I think. The context I'm using it is a little more complex, this is just an example. I have a tuple of tuples, and I want to return a reference to the first inner tuple that satisfies some trait.
    – tommaisey
    Nov 11 at 16:23


















For me it is unclear what your question is. What is wrong with std::get_if<float>(my_tuple)?
– mkaes
Nov 11 at 16:20




For me it is unclear what your question is. What is wrong with std::get_if<float>(my_tuple)?
– mkaes
Nov 11 at 16:20












That would be just std::get<float> (my_tuple), I think. The context I'm using it is a little more complex, this is just an example. I have a tuple of tuples, and I want to return a reference to the first inner tuple that satisfies some trait.
– tommaisey
Nov 11 at 16:23






That would be just std::get<float> (my_tuple), I think. The context I'm using it is a little more complex, this is just an example. I have a tuple of tuples, and I want to return a reference to the first inner tuple that satisfies some trait.
– tommaisey
Nov 11 at 16:23














3 Answers
3






active

oldest

votes

















up vote
1
down vote



accepted










Here's a surprisingly simple way without using recursion:



template <template <typename...> typename T, typename... Ts>
constexpr int index_of_integral(const T<Ts...>&)
{
const bool a = { std::is_integral_v<Ts>... };
for (int i = 0; i < sizeof...(Ts); ++i) if (a[i]) return i;
return -1;
}

template <typename T>
constexpr decltype(auto) get_if_integral(T&& t)
{
return std::get<index_of_integral(t)>(std::forward<T>(t));
}

int main()
{
constexpr auto t = std::make_tuple(3.14, 42, "xyzzy");
static_assert(get_if_integral(t) == 42);
}


It could easily be extended to be parametrized on the trait.



The only things that make it C++17 are the is_integral_v variable template and the single-argument static_assert. Everything else is C++14.



Note that in C++20 the for loop could be replaced with std::find and std::distance.



Ideally it should throw an exception instead of returning -1, but compilers don't seem to like that.



Inspired by this answer.






share|improve this answer





















  • That's very nifty indeed!
    – tommaisey
    Nov 12 at 20:35


















up vote
1
down vote













If I understand correctly what you want... I propose an helper struct gf_h ("get first helper") as follows



template <std::size_t, bool ...>
struct gf_h
{ };

template <std::size_t I, bool ... Bs>
struct gf_h<I, false, Bs...> : public gf_h<I+1u, Bs...>
{ };

template <std::size_t I, bool ... Bs>
struct gf_h<I, true, Bs...> : public std::integral_constant<std::size_t, I>
{ };


and a couple of functions that use it:



template <typename ... Us,
std::size_t I = gf_h<0, std::is_integral<Us>::value...>::value>
auto get_first_integral (std::tuple<Us...> const & t)
{ return std::get<I>(t); }

template <typename ... Us,
std::size_t I = gf_h<0, std::is_floating_point<Us>::value...>::value>
auto get_first_floating (std::tuple<Us...> const & t)
{ return std::get<I>(t); }


Observe that are SFINAE enabled/disabled functions, so are enabled only if there is an integral (or float) value in the tuple



The following is a full compiling example



#include <tuple>
#include <iostream>

template <std::size_t, bool ...>
struct gf_h
{ };

template <std::size_t I, bool ... Bs>
struct gf_h<I, false, Bs...> : public gf_h<I+1u, Bs...>
{ };

template <std::size_t I, bool ... Bs>
struct gf_h<I, true, Bs...> : public std::integral_constant<std::size_t, I>
{ };

template <typename ... Us,
std::size_t I = gf_h<0, std::is_integral<Us>::value...>::value>
auto get_first_integral (std::tuple<Us...> const & t)
{ return std::get<I>(t); }

template <typename ... Us,
std::size_t I = gf_h<0, std::is_floating_point<Us>::value...>::value>
auto get_first_floating (std::tuple<Us...> const & t)
{ return std::get<I>(t); }

int main()
{
auto tup1 = std::make_tuple(3.f, 2., 1, 0);

std::cout << get_first_integral(tup1) << std::endl; // 1
std::cout << get_first_floating(tup1) << std::endl; // 3

auto tup2 = std::make_tuple("abc", 4, 5);

std::cout << get_first_integral(tup2) << std::endl; // 4
// std::cout << get_first_floating(tup2) << std::endl; // error

auto tup3 = std::make_tuple("xyz", 6., 7.f);

// std::cout << get_first_integral(tup3) << std::endl; // error
std::cout << get_first_floating(tup3) << std::endl; // 6
}





share|improve this answer





















  • Ah very nice! This is easier to extend than the solution I found. Thank you very much!
    – tommaisey
    Nov 11 at 20:08


















up vote
0
down vote













Ok, I figured out a way to accomplish this in a way that is not generic over the trait, but that's good enough for my current purpose. Using if constexpr this really doesn't look too bad. I'm sure this isn't hugely idiomatic, but it works for me:



template <std::size_t Idx, typename... Us>
auto& get_if_integral_impl (std::tuple<Us...>& t)
{
static_assert (Idx < std::tuple_size_v<std::tuple<Us...>>,
"No integral elements in this tuple.");

if constexpr (std::is_integral<std::tuple_element_t<Idx, std::tuple<Us...>>>::value)
return std::get<Idx> (t);
else
return get_if_integral_impl<Idx + 1> (t);
}

template<typename... Us>
auto& get_if_integral (std::tuple<Us...>& t)
{
return get_if_integral_impl<0> (t);
}

auto tup = std::make_tuple (3.f, 2., 1, 0);
std::cout << get_if_integral (tup); // '1'


My use case is a little more complex, involving returning the first nested tuple which itself contains another type, but this should convey the basic idea.






share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53250540%2fget-first-element-of-stdtuple-satisfying-trait%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    1
    down vote



    accepted










    Here's a surprisingly simple way without using recursion:



    template <template <typename...> typename T, typename... Ts>
    constexpr int index_of_integral(const T<Ts...>&)
    {
    const bool a = { std::is_integral_v<Ts>... };
    for (int i = 0; i < sizeof...(Ts); ++i) if (a[i]) return i;
    return -1;
    }

    template <typename T>
    constexpr decltype(auto) get_if_integral(T&& t)
    {
    return std::get<index_of_integral(t)>(std::forward<T>(t));
    }

    int main()
    {
    constexpr auto t = std::make_tuple(3.14, 42, "xyzzy");
    static_assert(get_if_integral(t) == 42);
    }


    It could easily be extended to be parametrized on the trait.



    The only things that make it C++17 are the is_integral_v variable template and the single-argument static_assert. Everything else is C++14.



    Note that in C++20 the for loop could be replaced with std::find and std::distance.



    Ideally it should throw an exception instead of returning -1, but compilers don't seem to like that.



    Inspired by this answer.






    share|improve this answer





















    • That's very nifty indeed!
      – tommaisey
      Nov 12 at 20:35















    up vote
    1
    down vote



    accepted










    Here's a surprisingly simple way without using recursion:



    template <template <typename...> typename T, typename... Ts>
    constexpr int index_of_integral(const T<Ts...>&)
    {
    const bool a = { std::is_integral_v<Ts>... };
    for (int i = 0; i < sizeof...(Ts); ++i) if (a[i]) return i;
    return -1;
    }

    template <typename T>
    constexpr decltype(auto) get_if_integral(T&& t)
    {
    return std::get<index_of_integral(t)>(std::forward<T>(t));
    }

    int main()
    {
    constexpr auto t = std::make_tuple(3.14, 42, "xyzzy");
    static_assert(get_if_integral(t) == 42);
    }


    It could easily be extended to be parametrized on the trait.



    The only things that make it C++17 are the is_integral_v variable template and the single-argument static_assert. Everything else is C++14.



    Note that in C++20 the for loop could be replaced with std::find and std::distance.



    Ideally it should throw an exception instead of returning -1, but compilers don't seem to like that.



    Inspired by this answer.






    share|improve this answer





















    • That's very nifty indeed!
      – tommaisey
      Nov 12 at 20:35













    up vote
    1
    down vote



    accepted







    up vote
    1
    down vote



    accepted






    Here's a surprisingly simple way without using recursion:



    template <template <typename...> typename T, typename... Ts>
    constexpr int index_of_integral(const T<Ts...>&)
    {
    const bool a = { std::is_integral_v<Ts>... };
    for (int i = 0; i < sizeof...(Ts); ++i) if (a[i]) return i;
    return -1;
    }

    template <typename T>
    constexpr decltype(auto) get_if_integral(T&& t)
    {
    return std::get<index_of_integral(t)>(std::forward<T>(t));
    }

    int main()
    {
    constexpr auto t = std::make_tuple(3.14, 42, "xyzzy");
    static_assert(get_if_integral(t) == 42);
    }


    It could easily be extended to be parametrized on the trait.



    The only things that make it C++17 are the is_integral_v variable template and the single-argument static_assert. Everything else is C++14.



    Note that in C++20 the for loop could be replaced with std::find and std::distance.



    Ideally it should throw an exception instead of returning -1, but compilers don't seem to like that.



    Inspired by this answer.






    share|improve this answer












    Here's a surprisingly simple way without using recursion:



    template <template <typename...> typename T, typename... Ts>
    constexpr int index_of_integral(const T<Ts...>&)
    {
    const bool a = { std::is_integral_v<Ts>... };
    for (int i = 0; i < sizeof...(Ts); ++i) if (a[i]) return i;
    return -1;
    }

    template <typename T>
    constexpr decltype(auto) get_if_integral(T&& t)
    {
    return std::get<index_of_integral(t)>(std::forward<T>(t));
    }

    int main()
    {
    constexpr auto t = std::make_tuple(3.14, 42, "xyzzy");
    static_assert(get_if_integral(t) == 42);
    }


    It could easily be extended to be parametrized on the trait.



    The only things that make it C++17 are the is_integral_v variable template and the single-argument static_assert. Everything else is C++14.



    Note that in C++20 the for loop could be replaced with std::find and std::distance.



    Ideally it should throw an exception instead of returning -1, but compilers don't seem to like that.



    Inspired by this answer.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 11 at 22:58









    Oktalist

    9,86212648




    9,86212648












    • That's very nifty indeed!
      – tommaisey
      Nov 12 at 20:35


















    • That's very nifty indeed!
      – tommaisey
      Nov 12 at 20:35
















    That's very nifty indeed!
    – tommaisey
    Nov 12 at 20:35




    That's very nifty indeed!
    – tommaisey
    Nov 12 at 20:35












    up vote
    1
    down vote













    If I understand correctly what you want... I propose an helper struct gf_h ("get first helper") as follows



    template <std::size_t, bool ...>
    struct gf_h
    { };

    template <std::size_t I, bool ... Bs>
    struct gf_h<I, false, Bs...> : public gf_h<I+1u, Bs...>
    { };

    template <std::size_t I, bool ... Bs>
    struct gf_h<I, true, Bs...> : public std::integral_constant<std::size_t, I>
    { };


    and a couple of functions that use it:



    template <typename ... Us,
    std::size_t I = gf_h<0, std::is_integral<Us>::value...>::value>
    auto get_first_integral (std::tuple<Us...> const & t)
    { return std::get<I>(t); }

    template <typename ... Us,
    std::size_t I = gf_h<0, std::is_floating_point<Us>::value...>::value>
    auto get_first_floating (std::tuple<Us...> const & t)
    { return std::get<I>(t); }


    Observe that are SFINAE enabled/disabled functions, so are enabled only if there is an integral (or float) value in the tuple



    The following is a full compiling example



    #include <tuple>
    #include <iostream>

    template <std::size_t, bool ...>
    struct gf_h
    { };

    template <std::size_t I, bool ... Bs>
    struct gf_h<I, false, Bs...> : public gf_h<I+1u, Bs...>
    { };

    template <std::size_t I, bool ... Bs>
    struct gf_h<I, true, Bs...> : public std::integral_constant<std::size_t, I>
    { };

    template <typename ... Us,
    std::size_t I = gf_h<0, std::is_integral<Us>::value...>::value>
    auto get_first_integral (std::tuple<Us...> const & t)
    { return std::get<I>(t); }

    template <typename ... Us,
    std::size_t I = gf_h<0, std::is_floating_point<Us>::value...>::value>
    auto get_first_floating (std::tuple<Us...> const & t)
    { return std::get<I>(t); }

    int main()
    {
    auto tup1 = std::make_tuple(3.f, 2., 1, 0);

    std::cout << get_first_integral(tup1) << std::endl; // 1
    std::cout << get_first_floating(tup1) << std::endl; // 3

    auto tup2 = std::make_tuple("abc", 4, 5);

    std::cout << get_first_integral(tup2) << std::endl; // 4
    // std::cout << get_first_floating(tup2) << std::endl; // error

    auto tup3 = std::make_tuple("xyz", 6., 7.f);

    // std::cout << get_first_integral(tup3) << std::endl; // error
    std::cout << get_first_floating(tup3) << std::endl; // 6
    }





    share|improve this answer





















    • Ah very nice! This is easier to extend than the solution I found. Thank you very much!
      – tommaisey
      Nov 11 at 20:08















    up vote
    1
    down vote













    If I understand correctly what you want... I propose an helper struct gf_h ("get first helper") as follows



    template <std::size_t, bool ...>
    struct gf_h
    { };

    template <std::size_t I, bool ... Bs>
    struct gf_h<I, false, Bs...> : public gf_h<I+1u, Bs...>
    { };

    template <std::size_t I, bool ... Bs>
    struct gf_h<I, true, Bs...> : public std::integral_constant<std::size_t, I>
    { };


    and a couple of functions that use it:



    template <typename ... Us,
    std::size_t I = gf_h<0, std::is_integral<Us>::value...>::value>
    auto get_first_integral (std::tuple<Us...> const & t)
    { return std::get<I>(t); }

    template <typename ... Us,
    std::size_t I = gf_h<0, std::is_floating_point<Us>::value...>::value>
    auto get_first_floating (std::tuple<Us...> const & t)
    { return std::get<I>(t); }


    Observe that are SFINAE enabled/disabled functions, so are enabled only if there is an integral (or float) value in the tuple



    The following is a full compiling example



    #include <tuple>
    #include <iostream>

    template <std::size_t, bool ...>
    struct gf_h
    { };

    template <std::size_t I, bool ... Bs>
    struct gf_h<I, false, Bs...> : public gf_h<I+1u, Bs...>
    { };

    template <std::size_t I, bool ... Bs>
    struct gf_h<I, true, Bs...> : public std::integral_constant<std::size_t, I>
    { };

    template <typename ... Us,
    std::size_t I = gf_h<0, std::is_integral<Us>::value...>::value>
    auto get_first_integral (std::tuple<Us...> const & t)
    { return std::get<I>(t); }

    template <typename ... Us,
    std::size_t I = gf_h<0, std::is_floating_point<Us>::value...>::value>
    auto get_first_floating (std::tuple<Us...> const & t)
    { return std::get<I>(t); }

    int main()
    {
    auto tup1 = std::make_tuple(3.f, 2., 1, 0);

    std::cout << get_first_integral(tup1) << std::endl; // 1
    std::cout << get_first_floating(tup1) << std::endl; // 3

    auto tup2 = std::make_tuple("abc", 4, 5);

    std::cout << get_first_integral(tup2) << std::endl; // 4
    // std::cout << get_first_floating(tup2) << std::endl; // error

    auto tup3 = std::make_tuple("xyz", 6., 7.f);

    // std::cout << get_first_integral(tup3) << std::endl; // error
    std::cout << get_first_floating(tup3) << std::endl; // 6
    }





    share|improve this answer





















    • Ah very nice! This is easier to extend than the solution I found. Thank you very much!
      – tommaisey
      Nov 11 at 20:08













    up vote
    1
    down vote










    up vote
    1
    down vote









    If I understand correctly what you want... I propose an helper struct gf_h ("get first helper") as follows



    template <std::size_t, bool ...>
    struct gf_h
    { };

    template <std::size_t I, bool ... Bs>
    struct gf_h<I, false, Bs...> : public gf_h<I+1u, Bs...>
    { };

    template <std::size_t I, bool ... Bs>
    struct gf_h<I, true, Bs...> : public std::integral_constant<std::size_t, I>
    { };


    and a couple of functions that use it:



    template <typename ... Us,
    std::size_t I = gf_h<0, std::is_integral<Us>::value...>::value>
    auto get_first_integral (std::tuple<Us...> const & t)
    { return std::get<I>(t); }

    template <typename ... Us,
    std::size_t I = gf_h<0, std::is_floating_point<Us>::value...>::value>
    auto get_first_floating (std::tuple<Us...> const & t)
    { return std::get<I>(t); }


    Observe that are SFINAE enabled/disabled functions, so are enabled only if there is an integral (or float) value in the tuple



    The following is a full compiling example



    #include <tuple>
    #include <iostream>

    template <std::size_t, bool ...>
    struct gf_h
    { };

    template <std::size_t I, bool ... Bs>
    struct gf_h<I, false, Bs...> : public gf_h<I+1u, Bs...>
    { };

    template <std::size_t I, bool ... Bs>
    struct gf_h<I, true, Bs...> : public std::integral_constant<std::size_t, I>
    { };

    template <typename ... Us,
    std::size_t I = gf_h<0, std::is_integral<Us>::value...>::value>
    auto get_first_integral (std::tuple<Us...> const & t)
    { return std::get<I>(t); }

    template <typename ... Us,
    std::size_t I = gf_h<0, std::is_floating_point<Us>::value...>::value>
    auto get_first_floating (std::tuple<Us...> const & t)
    { return std::get<I>(t); }

    int main()
    {
    auto tup1 = std::make_tuple(3.f, 2., 1, 0);

    std::cout << get_first_integral(tup1) << std::endl; // 1
    std::cout << get_first_floating(tup1) << std::endl; // 3

    auto tup2 = std::make_tuple("abc", 4, 5);

    std::cout << get_first_integral(tup2) << std::endl; // 4
    // std::cout << get_first_floating(tup2) << std::endl; // error

    auto tup3 = std::make_tuple("xyz", 6., 7.f);

    // std::cout << get_first_integral(tup3) << std::endl; // error
    std::cout << get_first_floating(tup3) << std::endl; // 6
    }





    share|improve this answer












    If I understand correctly what you want... I propose an helper struct gf_h ("get first helper") as follows



    template <std::size_t, bool ...>
    struct gf_h
    { };

    template <std::size_t I, bool ... Bs>
    struct gf_h<I, false, Bs...> : public gf_h<I+1u, Bs...>
    { };

    template <std::size_t I, bool ... Bs>
    struct gf_h<I, true, Bs...> : public std::integral_constant<std::size_t, I>
    { };


    and a couple of functions that use it:



    template <typename ... Us,
    std::size_t I = gf_h<0, std::is_integral<Us>::value...>::value>
    auto get_first_integral (std::tuple<Us...> const & t)
    { return std::get<I>(t); }

    template <typename ... Us,
    std::size_t I = gf_h<0, std::is_floating_point<Us>::value...>::value>
    auto get_first_floating (std::tuple<Us...> const & t)
    { return std::get<I>(t); }


    Observe that are SFINAE enabled/disabled functions, so are enabled only if there is an integral (or float) value in the tuple



    The following is a full compiling example



    #include <tuple>
    #include <iostream>

    template <std::size_t, bool ...>
    struct gf_h
    { };

    template <std::size_t I, bool ... Bs>
    struct gf_h<I, false, Bs...> : public gf_h<I+1u, Bs...>
    { };

    template <std::size_t I, bool ... Bs>
    struct gf_h<I, true, Bs...> : public std::integral_constant<std::size_t, I>
    { };

    template <typename ... Us,
    std::size_t I = gf_h<0, std::is_integral<Us>::value...>::value>
    auto get_first_integral (std::tuple<Us...> const & t)
    { return std::get<I>(t); }

    template <typename ... Us,
    std::size_t I = gf_h<0, std::is_floating_point<Us>::value...>::value>
    auto get_first_floating (std::tuple<Us...> const & t)
    { return std::get<I>(t); }

    int main()
    {
    auto tup1 = std::make_tuple(3.f, 2., 1, 0);

    std::cout << get_first_integral(tup1) << std::endl; // 1
    std::cout << get_first_floating(tup1) << std::endl; // 3

    auto tup2 = std::make_tuple("abc", 4, 5);

    std::cout << get_first_integral(tup2) << std::endl; // 4
    // std::cout << get_first_floating(tup2) << std::endl; // error

    auto tup3 = std::make_tuple("xyz", 6., 7.f);

    // std::cout << get_first_integral(tup3) << std::endl; // error
    std::cout << get_first_floating(tup3) << std::endl; // 6
    }






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 11 at 19:57









    max66

    33.8k63762




    33.8k63762












    • Ah very nice! This is easier to extend than the solution I found. Thank you very much!
      – tommaisey
      Nov 11 at 20:08


















    • Ah very nice! This is easier to extend than the solution I found. Thank you very much!
      – tommaisey
      Nov 11 at 20:08
















    Ah very nice! This is easier to extend than the solution I found. Thank you very much!
    – tommaisey
    Nov 11 at 20:08




    Ah very nice! This is easier to extend than the solution I found. Thank you very much!
    – tommaisey
    Nov 11 at 20:08










    up vote
    0
    down vote













    Ok, I figured out a way to accomplish this in a way that is not generic over the trait, but that's good enough for my current purpose. Using if constexpr this really doesn't look too bad. I'm sure this isn't hugely idiomatic, but it works for me:



    template <std::size_t Idx, typename... Us>
    auto& get_if_integral_impl (std::tuple<Us...>& t)
    {
    static_assert (Idx < std::tuple_size_v<std::tuple<Us...>>,
    "No integral elements in this tuple.");

    if constexpr (std::is_integral<std::tuple_element_t<Idx, std::tuple<Us...>>>::value)
    return std::get<Idx> (t);
    else
    return get_if_integral_impl<Idx + 1> (t);
    }

    template<typename... Us>
    auto& get_if_integral (std::tuple<Us...>& t)
    {
    return get_if_integral_impl<0> (t);
    }

    auto tup = std::make_tuple (3.f, 2., 1, 0);
    std::cout << get_if_integral (tup); // '1'


    My use case is a little more complex, involving returning the first nested tuple which itself contains another type, but this should convey the basic idea.






    share|improve this answer

























      up vote
      0
      down vote













      Ok, I figured out a way to accomplish this in a way that is not generic over the trait, but that's good enough for my current purpose. Using if constexpr this really doesn't look too bad. I'm sure this isn't hugely idiomatic, but it works for me:



      template <std::size_t Idx, typename... Us>
      auto& get_if_integral_impl (std::tuple<Us...>& t)
      {
      static_assert (Idx < std::tuple_size_v<std::tuple<Us...>>,
      "No integral elements in this tuple.");

      if constexpr (std::is_integral<std::tuple_element_t<Idx, std::tuple<Us...>>>::value)
      return std::get<Idx> (t);
      else
      return get_if_integral_impl<Idx + 1> (t);
      }

      template<typename... Us>
      auto& get_if_integral (std::tuple<Us...>& t)
      {
      return get_if_integral_impl<0> (t);
      }

      auto tup = std::make_tuple (3.f, 2., 1, 0);
      std::cout << get_if_integral (tup); // '1'


      My use case is a little more complex, involving returning the first nested tuple which itself contains another type, but this should convey the basic idea.






      share|improve this answer























        up vote
        0
        down vote










        up vote
        0
        down vote









        Ok, I figured out a way to accomplish this in a way that is not generic over the trait, but that's good enough for my current purpose. Using if constexpr this really doesn't look too bad. I'm sure this isn't hugely idiomatic, but it works for me:



        template <std::size_t Idx, typename... Us>
        auto& get_if_integral_impl (std::tuple<Us...>& t)
        {
        static_assert (Idx < std::tuple_size_v<std::tuple<Us...>>,
        "No integral elements in this tuple.");

        if constexpr (std::is_integral<std::tuple_element_t<Idx, std::tuple<Us...>>>::value)
        return std::get<Idx> (t);
        else
        return get_if_integral_impl<Idx + 1> (t);
        }

        template<typename... Us>
        auto& get_if_integral (std::tuple<Us...>& t)
        {
        return get_if_integral_impl<0> (t);
        }

        auto tup = std::make_tuple (3.f, 2., 1, 0);
        std::cout << get_if_integral (tup); // '1'


        My use case is a little more complex, involving returning the first nested tuple which itself contains another type, but this should convey the basic idea.






        share|improve this answer












        Ok, I figured out a way to accomplish this in a way that is not generic over the trait, but that's good enough for my current purpose. Using if constexpr this really doesn't look too bad. I'm sure this isn't hugely idiomatic, but it works for me:



        template <std::size_t Idx, typename... Us>
        auto& get_if_integral_impl (std::tuple<Us...>& t)
        {
        static_assert (Idx < std::tuple_size_v<std::tuple<Us...>>,
        "No integral elements in this tuple.");

        if constexpr (std::is_integral<std::tuple_element_t<Idx, std::tuple<Us...>>>::value)
        return std::get<Idx> (t);
        else
        return get_if_integral_impl<Idx + 1> (t);
        }

        template<typename... Us>
        auto& get_if_integral (std::tuple<Us...>& t)
        {
        return get_if_integral_impl<0> (t);
        }

        auto tup = std::make_tuple (3.f, 2., 1, 0);
        std::cout << get_if_integral (tup); // '1'


        My use case is a little more complex, involving returning the first nested tuple which itself contains another type, but this should convey the basic idea.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 11 at 18:02









        tommaisey

        1317




        1317






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53250540%2fget-first-element-of-stdtuple-satisfying-trait%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Florida Star v. B. J. F.

            Danny Elfman

            Retrieve a Users Dashboard in Tumblr with R and TumblR. Oauth Issues