代码之家  ›  专栏  ›  技术社区  ›  Matt

如何在C++ 11中编写C++ 17静态COSTEXPR方法?

  •  0
  • Matt  · 技术社区  · 6 年前

    写下面的东西最简洁的方法是什么 static constexpr size_t Foo<>::sum() C++ 11中的方法?这在C++ 17编译器中很好,但是我正在寻找一种在C++ 11模式下工作在G++、CLAN和Visual Studio 2015上的方法。

    #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;
    }
    

    编译并运行:

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

    我可以为 sum() 这就完成了,但我真的希望它是 static constexpr 成员功能如上。在C++ 11中这是可能的吗?

    4 回复  |  直到 6 年前
        1
  •  5
  •   HolyBlackCat    6 年前

    我会写如下:

    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> {};
    

    它可以被包装成 static constexpr 功能简单:

    template <typename T, size_t N>
    constexpr size_t Foo<T, N>::sum()
    {
        return foo_sum<Foo<T, N>>::value;
    }
    
        2
  •  2
  •   Barry    6 年前

    另一种方法 HolyBlackCat's answer 是使用函数重载:

    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;
    }
    

    可能对眼睛比较容易。还可以使函数返回 integral_constant S而不是 size_t 有一些好处。

        3
  •  1
  •   jrok    6 年前

    带标签调度:

    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();
    };
    

    执行 sum :

    template<typename T,size_t N>
    constexpr size_t Foo<T,N>::sum()
    {
        return sum_impl( is_foo<T>{} );
    }
    
        4
  •  0
  •   max66    6 年前

    全套的怎么样 Foo 班级?

    你也可以避免 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;
    }
    

    --编辑——

    OP要求:

    实际上,foo是一个具有许多成员函数的大类。这是否需要重新澄清所有这些问题?

    不一定:您可以使用 ( Bar ,在下面的示例中)

    #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;
    }