c ++模板扣除头文件中指定模板的数组大小

时间:2017-01-08 02:26:36

标签: c++ c++11 templates static-members constexpr

我正在阅读Meyers关于现代c ++的书,在那里我发现代码片段可能很有用:

template <typename T, std::size_t N>
constexpr std::size_t arraySize(T (&) [N]) noexcept {
  return N;
}

此函数为我们推导N作为编译时常量。所以我想在我的代码中应用它:

template <typename T, std::size_t N>
constexpr std::size_t arraySize(T (&) [N]) noexcept {
  return N;
}

template <typename T>
class A {
  public:
    const static char* names[];
};

template<typename T>
const char* A<T>::names[] = {"foo", "bar"};

template<>
const char* A<bool>::names[] = {"foo","bar", "foobar"};

如果放入一个文件,它可以正常运行,arraySize(A<int>::names)2arraySize(A<bool>::names)3

但是当在需要单独的.h.cpp的大型项目中使用时,问题就出现了:

  1. 如果将A<bool>::names[]的指定版本的声明放在.cpp中,则代码会编译(和链接)但编译器在推断arraySize()时无法看到它,因此arraySize(A<bool>::names)推断为2

  2. 如果将A<bool>::names[]的声明放在.h中,我们会收到“重复符号”链接错误。

  3. 那么如何才能将arraySize(A<bool>::names)正确推断为3

2 个答案:

答案 0 :(得分:1)

您正在使用// does not work - Storage::putFile('public/image', $resize); // Storage::put($path, $contents, $visibility = null) Storage::put('public/image/myUniqueFileNameHere.jpg', $resize->__toString()); 功能,因此您正在使用C ++ 11(或更新版本)编译器。

因此,如果您的constexpr仅包含class A(否则您只能为names创建基类),则可以声明names和(专门化该类)你可以在body类中(在标题中)初始化它,并在正文之外定义它(在cpp文件中,如果你需要),而不用初始化它。

而且,如果我理解正确,从C ++ 17开始,不再需要类定义的外部。

以下是一个例子

static constexpr

---编辑---

OP写

  

对于有一个成员的班级来说,它很优雅。但是我的班级包含其他成员和方法,所以我会选择&#34;完成维度&#34;一个有问题的评论,因为这需要对原始代码进行最少的修改

我添加了一个修改过的示例,其中#include <iostream> template <typename T, std::size_t N> constexpr std::size_t arraySize(T (&) [N]) noexcept { return N; } template <typename T> class A { public: static constexpr char const * names[] = {"foo", "bar"}; }; template <> class A<bool> { public: static constexpr char const * names[] = {"foo", "bar", "foobar"}; }; template<typename T> constexpr char const * A<T>::names[]; constexpr char const * A<bool>::names[]; int main() { std::cout << arraySize(A<long>::names) << std::endl; // print 2 std::cout << arraySize(A<bool>::names) << std::endl; // print 3 } 插入到一个简单的模板基础结构(names,base-for-names)中,仅包含namesB

这允许仅针对简单的names进行专业化,并且仅针对复杂namesB进行一次开发。

class A

答案 1 :(得分:0)

您不能让类模板使用.cpp文件,它根本不适用于编译器的工作方式。编译器所做的是为每次向类发送新数据类型时生成一个版本。

所以基本上如果你有一个类模板接受一个变量,并且你创建了两个对象,一个带有int,一个带有类型的字符串,编译器将生成两个类的定义。问题是编译器也不知道用.cpp做这个。我听说您可以将.cpp重命名为其他任何内容,例如.tpp,或手动重载类定义。两种方式都有点hacky,每个人都只是在.h文件中编写模板类,这可能看起来与其他类不一致,但它就是这样的。