我正在阅读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的大型项目中使用时,问题就出现了:
>如果在.cpp中放置指定版本的A< bool> :: names []的声明,则代码编译(和链接)但编译器在推断arraySize()时无法看到它,因此arraySize(A< bool> :: names)推断为2.
>如果将A< bool> :: names []的声明放在.h中,当然,我们会收到“重复符号”链接错误.
那么如何才能将arraySize(A< bool> :: names)正确推导为3?
最佳答案 您正在使用constexpr函数,因此您正在使用C 11(或更新版本)编译器.
因此,如果您的类A只包含名称(否则您只能为名称创建基类),您可以声明它静态constexpr和(专门化类)您可以在body类(在标题中)初始化它并定义它身体外(在cpp文件中,如果你需要)没有初始化它.
而且,如果我理解正确,从C 17开始,不再需要类定义的外部.
以下是一个例子
#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
}
—编辑—
OP写
It is elegant for classes with one member. But my class contains other members and methods so I’ll go for “complete with the dimension” one in question’s comments, for that requires minimal modification of my original code
我添加了一个修改过的示例,其中名称插入到一个简单的模板基础结构(namesB,base-for-names)中,只包含名称.
这允许专门化仅用于简单的名称B和开发,只有一次,对于复杂的类A.
#include <iostream>
template <typename T, std::size_t N>
constexpr std::size_t arraySize(T (&) [N]) noexcept
{ return N; }
template <typename T>
struct namesB
{ static constexpr char const * names[] = {"foo", "bar"}; };
template <>
struct namesB<bool>
{ static constexpr char const * names[] = {"foo", "bar", "foobar"}; };
template <typename T>
class A : public namesB<T>
{ /* a complex class defined only one time */ };
template<typename T>
constexpr char const * namesB<T>::names[];
constexpr char const * namesB<bool>::names[];
int main()
{
std::cout << arraySize(A<long>::names) << std::endl; // print 2
std::cout << arraySize(A<bool>::names) << std::endl; // print 3
}