我正在阅读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)
为2
,arraySize(A<bool>::names)
为3
。
但是当在需要单独的.h
和.cpp
的大型项目中使用时,问题就出现了:
如果将A<bool>::names[]
的指定版本的声明放在.cpp
中,则代码会编译(和链接)但编译器在推断arraySize()
时无法看到它,因此arraySize(A<bool>::names)
推断为2
。
如果将A<bool>::names[]
的声明放在.h
中,我们会收到“重复符号”链接错误。
那么如何才能将arraySize(A<bool>::names)
正确推断为3
?
答案 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文件中编写模板类,这可能看起来与其他类不一致,但它就是这样的。