在源文件上定义"static constexpr"函数



我在一个头文件上有一个class,它的成员在一个pimpl类中定义。这个想法是我使用这个方法(基本上是std::aligned_storage_t和一个指针,但在声明对象时必须指定类的大小和对齐方式(在堆栈上分配pimpl类。我想让代码交叉编译器,所以猜测不是一个选项,所以我定义了两个privatestatic constexpr函数:impl_sizeimpl_align,它们在相应的源文件上定义,基本上返回sizeof(pimpl)alignof(pimpl)。问题是,我从MSVC(未在其他编译器上测试(中得到以下错误:

expression must have a constant value -- constexpr function function "Type::impl_size" (declared at line 70) is not defined

第70行是在报头上定义CCD_ 9的地方。

MCVE:

#include <cstddef>
template <typename T1, std::size_t N1, std::size_t N2>
struct Pimpl;
class Type
{
private:
static constexpr std::size_t impl_size() noexcept; // line 70
static constexpr std::size_t impl_align() noexcept;
struct impl {};
Pimpl<impl, impl_size(), impl_align()> data; // error happens here
};
constexpr std::size_t Type::impl_size() noexcept
{
return sizeof(Type::impl);
}
constexpr std::size_t Type::impl_align() noexcept
{
return alignof(Type::impl);
}

它是这么说的:当您声明成员函数constexpr时,您没有定义它。

必须立即在类定义中内联提供定义。

您的代码有几个问题,我觉得很奇怪。";PImpl";习惯用法是将接口与其实现解耦,通常是为了在实现发生变化时更容易进行编译。但是,通过在接口类中定义struct impl,并在同一类中的模板中使用它,实际上就是在强制实现与接口耦合。

sizeofalignof需要一个完整的类型,impl似乎不是(在撰写本文时EDITimpl只是前向声明的(,因此即使在修复了Type::impl_size()Type::impl_align()的问题后,您也会遇到此问题。

对于您的问题,一个即时且有点肤浅的解决方案是使impl成为一个完整的类型(并在声明时定义它(,并将impl_size()impl_align()变成inline static constexpr函数,这些函数也在现场定义:

class type
{
// ...
private:
struct impl {
// struct definition, so that impl is a complete type
};
inline static constexpr impl_size() noexcept {
return sizeof(impl);
}
inline static constexpr impl_align() noexcept {
return alignof(impl);
}

Pimpl<impl, impl_size(), impl_align()> data;
};

这仍然有点闻起来,因为impl_sizeimpl_align是毫无意义的样板,并且您的PImpl模板可以直接从其第一个参数中获得所有相同的信息

template<typename T>
class Pimpl {
static constexpr std::size_t Size = sizeof(T);
static constexpr std::size_t Alignment = alignof(T);
};
class type {
private:
struct impl {};

Pimpl<impl> data;
};

这当然也要求impl是一个完整的类型。如果struct impl是嵌套的cless,那么这无论如何都是必需的。

您似乎试图在这里进行某种类型擦除(或者您需要impl的大小和对齐是否还有其他充分的理由?(,但无意中引入了对所涉及的实现和类型的大量依赖。

我建议如下:在命名空间范围内转发声明impl类,并简单地使用std::unique_ptr<impl>实现。然后可以在实现文件中定义impl。请注意,std::unique_ptr不需要完整的类型。

#include <iostream>
#include <memory>
// header.hpp
struct impl;
class type {
public:
type();
void doThing();

private:
std::unique_ptr<impl> m_pImpl;
};
// source.cpp
struct impl {
void doThingImpl() {
std::cout << "Did a thing";
}
};
type::type()
: m_pImpl(std::make_unique<impl>()) {

}
void type::doThing() {
m_pImpl->doThingImpl();
}
int main(){
auto t = type{};
t.doThing();

return 0;
}

实时演示

最新更新