c++ - 在编译时求和嵌套模板参数

标签 c++ templates c++11

我正在寻找一种更好的方法来计算与嵌套模板类关联的数字模板参数的总和。我这里有一个可行的解决方案,但我想执行此操作不必创建这个额外的帮助程序模板类 DepthCalculator和部分特化DepthCalculator<double,N> :

#include <array>
#include <iostream>

template<typename T,size_t N>
struct DepthCalculator
{
  static constexpr size_t Calculate()
  {
    return N + T::Depth();
  }
};

template<size_t N>
struct DepthCalculator<double,N>
{
  static constexpr size_t Calculate()
  {
    return N;
  }
};

template<typename T,size_t N>
class A
{
  std::array<T,N> arr;
public:
  static constexpr size_t Depth()
  {
    return DepthCalculator<T,N>::Calculate();
  }
  // ...
  // Too many methods in A to write a separate specialization for.
};

int main()
{
  using U = A<A<A<double,3>,4>,5>;
  U x;
  constexpr size_t Depth = U::Depth(); // 3 + 4 + 5 = 12
  std::cout << "Depth is " << Depth << std::endl;
  A<double,Depth> y;
  // Do stuff with x and y
  return 0;
}

静态函数A::Depth()在编译时返回适当的深度,然后可以将其用作创建 A 的其他实例的参数.必须同时创建 DepthCalculator 似乎是一个困惑的 hack模板和专用于此目的的特化。

我知道我还可以使用不同的 Depth() 定义来创建 A 本身的特化。 , 但由于 A 中的方法数量,这更加困惑,其中大部分取决于模板参数。另一种选择是从 A 继承,然后专门化子类,但这对于看起来应该更简单的事情来说也似乎过于复杂。

是否有使用 C++11 的更清洁的解决方案?


摘要编辑

最后,这是我在工作项目中采用的解决方案:

#include <array>
#include <iostream>

template<typename T,size_t N>
class A
{
  std::array<T,N> arr;

  template<typename U>
  struct Get { };
  template<size_t M>
  struct Get<A<double,M>> { static constexpr size_t Depth() { return M; } };
  template<typename U,size_t M>
  struct Get<A<U,M>>
    { static constexpr size_t Depth() { return M + Get<U>::Depth(); } };

public:
  static constexpr size_t GetDepth()
  {
    return Get<A<T,N>>::Depth();
  }
  // ...
  // Too many methods in A to write a separate specialization for.
};

int main()
{
  using U = A<A<A<double,3>,4>,5>;
  U x;
  constexpr size_t Depth = U::GetDepth(); // 3 + 4 + 5 = 12
  std::cout << "Depth is " << Depth << std::endl;
  A<double,Depth> y;
  // Do stuff with x and y
  return 0;
}

Nir Friedman 对原因提出了一些很好的观点 GetDepth()应该是一个外部函数,但是在这种情况下还有其他 Get函数(未显示)是适当的成员函数,因此最有意义的是 GetDepth()也是一个成员函数。我还借鉴了 Nir ​​的想法,即拥有 Depth()。函数只调用自己,而不是 GetDepth()这会产生较少的循环依赖。

我选择 skypjack 的答案是因为它最直接地提供了我最初要求的内容。

最佳答案

你说:

I want to do this without having to create this extra helper template class DepthCalculator

所以,也许这个(最小的,有效的例子)适合你:

#include<type_traits>
#include<cassert>

template<class T, std::size_t N>
struct S {
    template<class U, std::size_t M>
    static constexpr
    typename std::enable_if<not std::is_arithmetic<U>::value, std::size_t>::type
    calc() {
        return M+U::calc();
    }

    template<typename U, std::size_t M>
    static constexpr
    typename std::enable_if<std::is_arithmetic<U>::value, std::size_t>::type
    calc() {
        return M;
    }

    static constexpr std::size_t calc() {
        return calc<T, N>();
    }
};

int main() {
    using U = S<S<S<double,3>,4>,5>;
    static_assert(U::calc() == 12, "oops");
    constexpr std::size_t d = U::calc();
    assert(d == 12);
}

我不确定我是否完全理解你的问题。
希望这能有所帮助。

如果您使用的是 C++14,您还可以使用:

template<class U, std::size_t M>
static constexpr
std::enable_if_t<not std::is_arithmetic<U>::value, std::size_t>

如果你使用的是 C++17,它会变成:

template<class U, std::size_t M>
static constexpr
std::enable_if_t<not std::is_arithmetic_v<U>, std::size_t>

这同样适用于其他 sfinaed 返回类型。

关于c++ - 在编译时求和嵌套模板参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36777189/

相关文章:

c++ - OpenGL 光照不着色

c++ - 使用 strlen 时不为空终止符添加 +1 会导致在使用 send 时发送额外的垃圾字节

c++ - 使用带 std::thread 的 SFML 的编译器错误

c++ - 循环计算矩形的面积公式

c++ - 如何将 `std::chrono::milliseconds` 转换为 `boost::posix_time::milliseconds`

C++ 二进制表达式的无效操作数

c++ - 在 htmlcxx 中查找 'strings.h' 时出错

azure - 如何解决 ARM 模板中的 'resource is not defined in the template.' 错误?

c++ - 模板特化 - MSVC 和 GCC/MinGW 之间的不同行为

c++ - 模板常量/非常量参数转换