How to write this C++17 static constexpr method in C++11?












0















What is the most concise way to write the below static constexpr size_t Foo<>::sum() method in C++11? This works fine with C++17 compilers, but I'm looking for a way that works on g++, clang, and Visual Studio 2015 in C++11 mode.



#include <iostream>
#include <type_traits>

template<typename T,size_t N>
class Foo
{
public:
static constexpr size_t sum();
};

template<typename>
struct is_foo : std::false_type { };
template<typename T,size_t N>
struct is_foo<Foo<T,N>> : std::true_type { };

template<typename T,size_t N>
constexpr size_t Foo<T,N>::sum()
{
if constexpr (is_foo<T>::value)
return N + T::sum();
else
return N;
}

int main()
{
constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
std::cout << "sum = " << sum << std::endl;
return 0;
}


Compile and run:



$ g++ --version
g++ (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)
...
$ g++ -std=c++17 sum.cpp
$ ./a.out
sum = 12


I'm able to write an external functor for sum() that accomplishes this, but I would really like for it to be a static constexpr member function as above. Is this even possible in C++11?










share|improve this question

























  • You're just asking how to replace the if constexpr then, right? enable_if?

    – Lightness Races in Orbit
    Jan 1 at 21:19











  • I tried SFINAE with constexpr typename std::enable_if<is_foo<T>::value,size_t>::type Foo<T,N>::sum() but am getting the error prototype for 'constexpr typename std::enable_if<is_foo< <template-parameter-1-1> >::value, long unsigned int>::type Foo<T, N>::sum()' does not match any in class 'Foo<T, N>'.

    – Matt
    Jan 2 at 15:59


















0















What is the most concise way to write the below static constexpr size_t Foo<>::sum() method in C++11? This works fine with C++17 compilers, but I'm looking for a way that works on g++, clang, and Visual Studio 2015 in C++11 mode.



#include <iostream>
#include <type_traits>

template<typename T,size_t N>
class Foo
{
public:
static constexpr size_t sum();
};

template<typename>
struct is_foo : std::false_type { };
template<typename T,size_t N>
struct is_foo<Foo<T,N>> : std::true_type { };

template<typename T,size_t N>
constexpr size_t Foo<T,N>::sum()
{
if constexpr (is_foo<T>::value)
return N + T::sum();
else
return N;
}

int main()
{
constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
std::cout << "sum = " << sum << std::endl;
return 0;
}


Compile and run:



$ g++ --version
g++ (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)
...
$ g++ -std=c++17 sum.cpp
$ ./a.out
sum = 12


I'm able to write an external functor for sum() that accomplishes this, but I would really like for it to be a static constexpr member function as above. Is this even possible in C++11?










share|improve this question

























  • You're just asking how to replace the if constexpr then, right? enable_if?

    – Lightness Races in Orbit
    Jan 1 at 21:19











  • I tried SFINAE with constexpr typename std::enable_if<is_foo<T>::value,size_t>::type Foo<T,N>::sum() but am getting the error prototype for 'constexpr typename std::enable_if<is_foo< <template-parameter-1-1> >::value, long unsigned int>::type Foo<T, N>::sum()' does not match any in class 'Foo<T, N>'.

    – Matt
    Jan 2 at 15:59
















0












0








0








What is the most concise way to write the below static constexpr size_t Foo<>::sum() method in C++11? This works fine with C++17 compilers, but I'm looking for a way that works on g++, clang, and Visual Studio 2015 in C++11 mode.



#include <iostream>
#include <type_traits>

template<typename T,size_t N>
class Foo
{
public:
static constexpr size_t sum();
};

template<typename>
struct is_foo : std::false_type { };
template<typename T,size_t N>
struct is_foo<Foo<T,N>> : std::true_type { };

template<typename T,size_t N>
constexpr size_t Foo<T,N>::sum()
{
if constexpr (is_foo<T>::value)
return N + T::sum();
else
return N;
}

int main()
{
constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
std::cout << "sum = " << sum << std::endl;
return 0;
}


Compile and run:



$ g++ --version
g++ (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)
...
$ g++ -std=c++17 sum.cpp
$ ./a.out
sum = 12


I'm able to write an external functor for sum() that accomplishes this, but I would really like for it to be a static constexpr member function as above. Is this even possible in C++11?










share|improve this question
















What is the most concise way to write the below static constexpr size_t Foo<>::sum() method in C++11? This works fine with C++17 compilers, but I'm looking for a way that works on g++, clang, and Visual Studio 2015 in C++11 mode.



#include <iostream>
#include <type_traits>

template<typename T,size_t N>
class Foo
{
public:
static constexpr size_t sum();
};

template<typename>
struct is_foo : std::false_type { };
template<typename T,size_t N>
struct is_foo<Foo<T,N>> : std::true_type { };

template<typename T,size_t N>
constexpr size_t Foo<T,N>::sum()
{
if constexpr (is_foo<T>::value)
return N + T::sum();
else
return N;
}

int main()
{
constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
std::cout << "sum = " << sum << std::endl;
return 0;
}


Compile and run:



$ g++ --version
g++ (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)
...
$ g++ -std=c++17 sum.cpp
$ ./a.out
sum = 12


I'm able to write an external functor for sum() that accomplishes this, but I would really like for it to be a static constexpr member function as above. Is this even possible in C++11?







c++ c++11 templates c++17 template-meta-programming






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 1 at 22:09









max66

37.9k74471




37.9k74471










asked Jan 1 at 21:08









MattMatt

15.6k13751




15.6k13751













  • You're just asking how to replace the if constexpr then, right? enable_if?

    – Lightness Races in Orbit
    Jan 1 at 21:19











  • I tried SFINAE with constexpr typename std::enable_if<is_foo<T>::value,size_t>::type Foo<T,N>::sum() but am getting the error prototype for 'constexpr typename std::enable_if<is_foo< <template-parameter-1-1> >::value, long unsigned int>::type Foo<T, N>::sum()' does not match any in class 'Foo<T, N>'.

    – Matt
    Jan 2 at 15:59





















  • You're just asking how to replace the if constexpr then, right? enable_if?

    – Lightness Races in Orbit
    Jan 1 at 21:19











  • I tried SFINAE with constexpr typename std::enable_if<is_foo<T>::value,size_t>::type Foo<T,N>::sum() but am getting the error prototype for 'constexpr typename std::enable_if<is_foo< <template-parameter-1-1> >::value, long unsigned int>::type Foo<T, N>::sum()' does not match any in class 'Foo<T, N>'.

    – Matt
    Jan 2 at 15:59



















You're just asking how to replace the if constexpr then, right? enable_if?

– Lightness Races in Orbit
Jan 1 at 21:19





You're just asking how to replace the if constexpr then, right? enable_if?

– Lightness Races in Orbit
Jan 1 at 21:19













I tried SFINAE with constexpr typename std::enable_if<is_foo<T>::value,size_t>::type Foo<T,N>::sum() but am getting the error prototype for 'constexpr typename std::enable_if<is_foo< <template-parameter-1-1> >::value, long unsigned int>::type Foo<T, N>::sum()' does not match any in class 'Foo<T, N>'.

– Matt
Jan 2 at 15:59







I tried SFINAE with constexpr typename std::enable_if<is_foo<T>::value,size_t>::type Foo<T,N>::sum() but am getting the error prototype for 'constexpr typename std::enable_if<is_foo< <template-parameter-1-1> >::value, long unsigned int>::type Foo<T, N>::sum()' does not match any in class 'Foo<T, N>'.

– Matt
Jan 2 at 15:59














4 Answers
4






active

oldest

votes


















5














I'd write it as following:



template <typename>
struct foo_sum : std::integral_constant<size_t, 0> {};

template <typename T, size_t N>
struct foo_sum<Foo<T, N>> : std::integral_constant<size_t, foo_sum<T>::value + N> {};


It can be wrapped into a static constexpr function easily:



template <typename T, size_t N>
constexpr size_t Foo<T, N>::sum()
{
return foo_sum<Foo<T, N>>::value;
}





share|improve this answer
























  • This is nice...

    – jrok
    Jan 1 at 21:48











  • This does work. On Visual Studio 2015, I was getting the infamous C1001 fatal error but through shuffling some surrounding code, it compiled. Never encountered a problem with gcc or clang. Thank you!

    – Matt
    Jan 3 at 1:53



















2














An alternative approach to HolyBlackCat's answer is to use function overloading:



template <typename> struct tag {};

template <typename T>
constexpr size_t sum(tag<T>) {
return 0;
}

template <typename T, size_t N>
constexpr size_t sum(tag<Foo<T,N>>) {
return sum(tag<T>{}) + N;
}


Might be a little easier on the eyes. Could also make the functions return integral_constants instead of size_t, which has some benefits.






share|improve this answer































    1














    With tag dispatching:



    template<typename T,size_t N>
    class Foo
    {
    static constexpr size_t sum_impl(std::true_type) { return N + T::sum(); }
    static constexpr size_t sum_impl(std::false_type) { return N; };
    public:
    static constexpr size_t sum();
    };


    Implementation of sum:



    template<typename T,size_t N>
    constexpr size_t Foo<T,N>::sum()
    {
    return sum_impl( is_foo<T>{} );
    }





    share|improve this answer
























    • I've tried this approach, and indeed it does work on g++ and clang. For some reason, Visual Studio 2015 still tries to compile sum_impl(std::true_type) and results in a compiler error when T=double.

      – Matt
      Jan 1 at 21:34











    • @Matt Shame. This example seems to work with newer MSVC.

      – jrok
      Jan 1 at 21:45











    • @Matt Try making the first sum_impl a template itself.

      – jrok
      Jan 1 at 21:53



















    0














    What about specializing the full Foo class ?



    You can also avoid is_foo.



    #include <iostream>
    #include <type_traits>

    template <typename, std::size_t N>
    struct Foo
    { static constexpr std::size_t sum () { return N; } };

    template <typename T, std::size_t N1, std::size_t N2>
    struct Foo<Foo<T, N1>, N2>
    { static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };

    int main()
    {
    constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
    std::cout << "sum = " << sum << std::endl;
    return 0;
    }


    -- EDIT --



    The OP ask:




    In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?




    Not necessarily: you can do the trick with a base class/struct of Foo (Bar, in the following example)



    #include <iostream>
    #include <type_traits>

    template <typename T, std::size_t N>
    struct Foo;

    template <typename, std::size_t N>
    struct Bar
    { static constexpr std::size_t sum () { return N; } };

    template <typename T, std::size_t N1, std::size_t N2>
    struct Bar<Foo<T, N1>, N2>
    { static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };

    template <typename T, std::size_t N>
    struct Foo : public Bar<T, N>
    { /* many common member and methods */};

    int main()
    {
    constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
    std::cout << "sum = " << sum << std::endl;
    return 0;
    }





    share|improve this answer


























    • In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?

      – Matt
      Jan 1 at 21:53











    • @Matt - answer improved; hope this helps.

      – max66
      Jan 1 at 21:59











    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',
    autoActivateHeartbeat: false,
    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%2f53998958%2fhow-to-write-this-c17-static-constexpr-method-in-c11%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    4 Answers
    4






    active

    oldest

    votes








    4 Answers
    4






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    5














    I'd write it as following:



    template <typename>
    struct foo_sum : std::integral_constant<size_t, 0> {};

    template <typename T, size_t N>
    struct foo_sum<Foo<T, N>> : std::integral_constant<size_t, foo_sum<T>::value + N> {};


    It can be wrapped into a static constexpr function easily:



    template <typename T, size_t N>
    constexpr size_t Foo<T, N>::sum()
    {
    return foo_sum<Foo<T, N>>::value;
    }





    share|improve this answer
























    • This is nice...

      – jrok
      Jan 1 at 21:48











    • This does work. On Visual Studio 2015, I was getting the infamous C1001 fatal error but through shuffling some surrounding code, it compiled. Never encountered a problem with gcc or clang. Thank you!

      – Matt
      Jan 3 at 1:53
















    5














    I'd write it as following:



    template <typename>
    struct foo_sum : std::integral_constant<size_t, 0> {};

    template <typename T, size_t N>
    struct foo_sum<Foo<T, N>> : std::integral_constant<size_t, foo_sum<T>::value + N> {};


    It can be wrapped into a static constexpr function easily:



    template <typename T, size_t N>
    constexpr size_t Foo<T, N>::sum()
    {
    return foo_sum<Foo<T, N>>::value;
    }





    share|improve this answer
























    • This is nice...

      – jrok
      Jan 1 at 21:48











    • This does work. On Visual Studio 2015, I was getting the infamous C1001 fatal error but through shuffling some surrounding code, it compiled. Never encountered a problem with gcc or clang. Thank you!

      – Matt
      Jan 3 at 1:53














    5












    5








    5







    I'd write it as following:



    template <typename>
    struct foo_sum : std::integral_constant<size_t, 0> {};

    template <typename T, size_t N>
    struct foo_sum<Foo<T, N>> : std::integral_constant<size_t, foo_sum<T>::value + N> {};


    It can be wrapped into a static constexpr function easily:



    template <typename T, size_t N>
    constexpr size_t Foo<T, N>::sum()
    {
    return foo_sum<Foo<T, N>>::value;
    }





    share|improve this answer













    I'd write it as following:



    template <typename>
    struct foo_sum : std::integral_constant<size_t, 0> {};

    template <typename T, size_t N>
    struct foo_sum<Foo<T, N>> : std::integral_constant<size_t, foo_sum<T>::value + N> {};


    It can be wrapped into a static constexpr function easily:



    template <typename T, size_t N>
    constexpr size_t Foo<T, N>::sum()
    {
    return foo_sum<Foo<T, N>>::value;
    }






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Jan 1 at 21:19









    HolyBlackCatHolyBlackCat

    16.8k33468




    16.8k33468













    • This is nice...

      – jrok
      Jan 1 at 21:48











    • This does work. On Visual Studio 2015, I was getting the infamous C1001 fatal error but through shuffling some surrounding code, it compiled. Never encountered a problem with gcc or clang. Thank you!

      – Matt
      Jan 3 at 1:53



















    • This is nice...

      – jrok
      Jan 1 at 21:48











    • This does work. On Visual Studio 2015, I was getting the infamous C1001 fatal error but through shuffling some surrounding code, it compiled. Never encountered a problem with gcc or clang. Thank you!

      – Matt
      Jan 3 at 1:53

















    This is nice...

    – jrok
    Jan 1 at 21:48





    This is nice...

    – jrok
    Jan 1 at 21:48













    This does work. On Visual Studio 2015, I was getting the infamous C1001 fatal error but through shuffling some surrounding code, it compiled. Never encountered a problem with gcc or clang. Thank you!

    – Matt
    Jan 3 at 1:53





    This does work. On Visual Studio 2015, I was getting the infamous C1001 fatal error but through shuffling some surrounding code, it compiled. Never encountered a problem with gcc or clang. Thank you!

    – Matt
    Jan 3 at 1:53













    2














    An alternative approach to HolyBlackCat's answer is to use function overloading:



    template <typename> struct tag {};

    template <typename T>
    constexpr size_t sum(tag<T>) {
    return 0;
    }

    template <typename T, size_t N>
    constexpr size_t sum(tag<Foo<T,N>>) {
    return sum(tag<T>{}) + N;
    }


    Might be a little easier on the eyes. Could also make the functions return integral_constants instead of size_t, which has some benefits.






    share|improve this answer




























      2














      An alternative approach to HolyBlackCat's answer is to use function overloading:



      template <typename> struct tag {};

      template <typename T>
      constexpr size_t sum(tag<T>) {
      return 0;
      }

      template <typename T, size_t N>
      constexpr size_t sum(tag<Foo<T,N>>) {
      return sum(tag<T>{}) + N;
      }


      Might be a little easier on the eyes. Could also make the functions return integral_constants instead of size_t, which has some benefits.






      share|improve this answer


























        2












        2








        2







        An alternative approach to HolyBlackCat's answer is to use function overloading:



        template <typename> struct tag {};

        template <typename T>
        constexpr size_t sum(tag<T>) {
        return 0;
        }

        template <typename T, size_t N>
        constexpr size_t sum(tag<Foo<T,N>>) {
        return sum(tag<T>{}) + N;
        }


        Might be a little easier on the eyes. Could also make the functions return integral_constants instead of size_t, which has some benefits.






        share|improve this answer













        An alternative approach to HolyBlackCat's answer is to use function overloading:



        template <typename> struct tag {};

        template <typename T>
        constexpr size_t sum(tag<T>) {
        return 0;
        }

        template <typename T, size_t N>
        constexpr size_t sum(tag<Foo<T,N>>) {
        return sum(tag<T>{}) + N;
        }


        Might be a little easier on the eyes. Could also make the functions return integral_constants instead of size_t, which has some benefits.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Jan 1 at 23:36









        BarryBarry

        184k21323593




        184k21323593























            1














            With tag dispatching:



            template<typename T,size_t N>
            class Foo
            {
            static constexpr size_t sum_impl(std::true_type) { return N + T::sum(); }
            static constexpr size_t sum_impl(std::false_type) { return N; };
            public:
            static constexpr size_t sum();
            };


            Implementation of sum:



            template<typename T,size_t N>
            constexpr size_t Foo<T,N>::sum()
            {
            return sum_impl( is_foo<T>{} );
            }





            share|improve this answer
























            • I've tried this approach, and indeed it does work on g++ and clang. For some reason, Visual Studio 2015 still tries to compile sum_impl(std::true_type) and results in a compiler error when T=double.

              – Matt
              Jan 1 at 21:34











            • @Matt Shame. This example seems to work with newer MSVC.

              – jrok
              Jan 1 at 21:45











            • @Matt Try making the first sum_impl a template itself.

              – jrok
              Jan 1 at 21:53
















            1














            With tag dispatching:



            template<typename T,size_t N>
            class Foo
            {
            static constexpr size_t sum_impl(std::true_type) { return N + T::sum(); }
            static constexpr size_t sum_impl(std::false_type) { return N; };
            public:
            static constexpr size_t sum();
            };


            Implementation of sum:



            template<typename T,size_t N>
            constexpr size_t Foo<T,N>::sum()
            {
            return sum_impl( is_foo<T>{} );
            }





            share|improve this answer
























            • I've tried this approach, and indeed it does work on g++ and clang. For some reason, Visual Studio 2015 still tries to compile sum_impl(std::true_type) and results in a compiler error when T=double.

              – Matt
              Jan 1 at 21:34











            • @Matt Shame. This example seems to work with newer MSVC.

              – jrok
              Jan 1 at 21:45











            • @Matt Try making the first sum_impl a template itself.

              – jrok
              Jan 1 at 21:53














            1












            1








            1







            With tag dispatching:



            template<typename T,size_t N>
            class Foo
            {
            static constexpr size_t sum_impl(std::true_type) { return N + T::sum(); }
            static constexpr size_t sum_impl(std::false_type) { return N; };
            public:
            static constexpr size_t sum();
            };


            Implementation of sum:



            template<typename T,size_t N>
            constexpr size_t Foo<T,N>::sum()
            {
            return sum_impl( is_foo<T>{} );
            }





            share|improve this answer













            With tag dispatching:



            template<typename T,size_t N>
            class Foo
            {
            static constexpr size_t sum_impl(std::true_type) { return N + T::sum(); }
            static constexpr size_t sum_impl(std::false_type) { return N; };
            public:
            static constexpr size_t sum();
            };


            Implementation of sum:



            template<typename T,size_t N>
            constexpr size_t Foo<T,N>::sum()
            {
            return sum_impl( is_foo<T>{} );
            }






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Jan 1 at 21:29









            jrokjrok

            45.7k687121




            45.7k687121













            • I've tried this approach, and indeed it does work on g++ and clang. For some reason, Visual Studio 2015 still tries to compile sum_impl(std::true_type) and results in a compiler error when T=double.

              – Matt
              Jan 1 at 21:34











            • @Matt Shame. This example seems to work with newer MSVC.

              – jrok
              Jan 1 at 21:45











            • @Matt Try making the first sum_impl a template itself.

              – jrok
              Jan 1 at 21:53



















            • I've tried this approach, and indeed it does work on g++ and clang. For some reason, Visual Studio 2015 still tries to compile sum_impl(std::true_type) and results in a compiler error when T=double.

              – Matt
              Jan 1 at 21:34











            • @Matt Shame. This example seems to work with newer MSVC.

              – jrok
              Jan 1 at 21:45











            • @Matt Try making the first sum_impl a template itself.

              – jrok
              Jan 1 at 21:53

















            I've tried this approach, and indeed it does work on g++ and clang. For some reason, Visual Studio 2015 still tries to compile sum_impl(std::true_type) and results in a compiler error when T=double.

            – Matt
            Jan 1 at 21:34





            I've tried this approach, and indeed it does work on g++ and clang. For some reason, Visual Studio 2015 still tries to compile sum_impl(std::true_type) and results in a compiler error when T=double.

            – Matt
            Jan 1 at 21:34













            @Matt Shame. This example seems to work with newer MSVC.

            – jrok
            Jan 1 at 21:45





            @Matt Shame. This example seems to work with newer MSVC.

            – jrok
            Jan 1 at 21:45













            @Matt Try making the first sum_impl a template itself.

            – jrok
            Jan 1 at 21:53





            @Matt Try making the first sum_impl a template itself.

            – jrok
            Jan 1 at 21:53











            0














            What about specializing the full Foo class ?



            You can also avoid is_foo.



            #include <iostream>
            #include <type_traits>

            template <typename, std::size_t N>
            struct Foo
            { static constexpr std::size_t sum () { return N; } };

            template <typename T, std::size_t N1, std::size_t N2>
            struct Foo<Foo<T, N1>, N2>
            { static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };

            int main()
            {
            constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
            std::cout << "sum = " << sum << std::endl;
            return 0;
            }


            -- EDIT --



            The OP ask:




            In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?




            Not necessarily: you can do the trick with a base class/struct of Foo (Bar, in the following example)



            #include <iostream>
            #include <type_traits>

            template <typename T, std::size_t N>
            struct Foo;

            template <typename, std::size_t N>
            struct Bar
            { static constexpr std::size_t sum () { return N; } };

            template <typename T, std::size_t N1, std::size_t N2>
            struct Bar<Foo<T, N1>, N2>
            { static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };

            template <typename T, std::size_t N>
            struct Foo : public Bar<T, N>
            { /* many common member and methods */};

            int main()
            {
            constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
            std::cout << "sum = " << sum << std::endl;
            return 0;
            }





            share|improve this answer


























            • In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?

              – Matt
              Jan 1 at 21:53











            • @Matt - answer improved; hope this helps.

              – max66
              Jan 1 at 21:59
















            0














            What about specializing the full Foo class ?



            You can also avoid is_foo.



            #include <iostream>
            #include <type_traits>

            template <typename, std::size_t N>
            struct Foo
            { static constexpr std::size_t sum () { return N; } };

            template <typename T, std::size_t N1, std::size_t N2>
            struct Foo<Foo<T, N1>, N2>
            { static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };

            int main()
            {
            constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
            std::cout << "sum = " << sum << std::endl;
            return 0;
            }


            -- EDIT --



            The OP ask:




            In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?




            Not necessarily: you can do the trick with a base class/struct of Foo (Bar, in the following example)



            #include <iostream>
            #include <type_traits>

            template <typename T, std::size_t N>
            struct Foo;

            template <typename, std::size_t N>
            struct Bar
            { static constexpr std::size_t sum () { return N; } };

            template <typename T, std::size_t N1, std::size_t N2>
            struct Bar<Foo<T, N1>, N2>
            { static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };

            template <typename T, std::size_t N>
            struct Foo : public Bar<T, N>
            { /* many common member and methods */};

            int main()
            {
            constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
            std::cout << "sum = " << sum << std::endl;
            return 0;
            }





            share|improve this answer


























            • In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?

              – Matt
              Jan 1 at 21:53











            • @Matt - answer improved; hope this helps.

              – max66
              Jan 1 at 21:59














            0












            0








            0







            What about specializing the full Foo class ?



            You can also avoid is_foo.



            #include <iostream>
            #include <type_traits>

            template <typename, std::size_t N>
            struct Foo
            { static constexpr std::size_t sum () { return N; } };

            template <typename T, std::size_t N1, std::size_t N2>
            struct Foo<Foo<T, N1>, N2>
            { static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };

            int main()
            {
            constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
            std::cout << "sum = " << sum << std::endl;
            return 0;
            }


            -- EDIT --



            The OP ask:




            In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?




            Not necessarily: you can do the trick with a base class/struct of Foo (Bar, in the following example)



            #include <iostream>
            #include <type_traits>

            template <typename T, std::size_t N>
            struct Foo;

            template <typename, std::size_t N>
            struct Bar
            { static constexpr std::size_t sum () { return N; } };

            template <typename T, std::size_t N1, std::size_t N2>
            struct Bar<Foo<T, N1>, N2>
            { static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };

            template <typename T, std::size_t N>
            struct Foo : public Bar<T, N>
            { /* many common member and methods */};

            int main()
            {
            constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
            std::cout << "sum = " << sum << std::endl;
            return 0;
            }





            share|improve this answer















            What about specializing the full Foo class ?



            You can also avoid is_foo.



            #include <iostream>
            #include <type_traits>

            template <typename, std::size_t N>
            struct Foo
            { static constexpr std::size_t sum () { return N; } };

            template <typename T, std::size_t N1, std::size_t N2>
            struct Foo<Foo<T, N1>, N2>
            { static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };

            int main()
            {
            constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
            std::cout << "sum = " << sum << std::endl;
            return 0;
            }


            -- EDIT --



            The OP ask:




            In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?




            Not necessarily: you can do the trick with a base class/struct of Foo (Bar, in the following example)



            #include <iostream>
            #include <type_traits>

            template <typename T, std::size_t N>
            struct Foo;

            template <typename, std::size_t N>
            struct Bar
            { static constexpr std::size_t sum () { return N; } };

            template <typename T, std::size_t N1, std::size_t N2>
            struct Bar<Foo<T, N1>, N2>
            { static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };

            template <typename T, std::size_t N>
            struct Foo : public Bar<T, N>
            { /* many common member and methods */};

            int main()
            {
            constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
            std::cout << "sum = " << sum << std::endl;
            return 0;
            }






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Jan 1 at 21:59

























            answered Jan 1 at 21:30









            max66max66

            37.9k74471




            37.9k74471













            • In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?

              – Matt
              Jan 1 at 21:53











            • @Matt - answer improved; hope this helps.

              – max66
              Jan 1 at 21:59



















            • In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?

              – Matt
              Jan 1 at 21:53











            • @Matt - answer improved; hope this helps.

              – max66
              Jan 1 at 21:59

















            In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?

            – Matt
            Jan 1 at 21:53





            In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?

            – Matt
            Jan 1 at 21:53













            @Matt - answer improved; hope this helps.

            – max66
            Jan 1 at 21:59





            @Matt - answer improved; hope this helps.

            – max66
            Jan 1 at 21:59


















            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.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53998958%2fhow-to-write-this-c17-static-constexpr-method-in-c11%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

            Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

            Does disintegrating a polymorphed enemy still kill it after the 2018 errata?

            A Topological Invariant for $pi_3(U(n))$