在模板类中使用 std::conditional 的问题

问题描述

我正在尝试使用非类型模板参数定义模板类。然后我使用 std::conditional 从这个模板参数确定这个类的成员的类型。我遇到了一些编译时错误

下面是 MWE。在此 MWE 中,我试图根据条件为真(结构化)或 FiniteElementList,使模板类 Mesh 的成员 std::vector分别为假(非结构化)。类 std::list 包含一些成员函数和友元函数,这些函数只是暂时声明,可能会在稍后阶段定义。

MWE

Mesh

编译:

我正在尝试使用 clang 编译器进行编译,如下所示

// c++ standard library headers #include <list> // std::list #include <type_traits> // std::conditional #include <vector> // std::vector // (un)structured flag enum class StructuredUnstructured { kStructured = true,kUnstructured = false }; // (un)structured mesh template <StructuredUnstructured is_structured> class Mesh { using Element = double; using FiniteElementList = typename std::conditional<is_structured == StructuredUnstructured::kStructured,std::vector<Element>,std::list<Element>>::type; public: // constructors Mesh() = default; Mesh(const Mesh& m) = default; // copy constructor Mesh(Mesh&& m) noexcept = default; // move constructor // assignment operators Mesh& operator=(const Mesh& m) = default; // copy assignment Mesh& operator=(Mesh&& m) noexcept = default; // move assignment ~Mesh() = default; void Indexing() {} void Properties() {} friend Mesh ReadMesh() {} friend void WriteMesh() {} friend void WriteMeshVTK() {} private: FiniteElementList finite_elements_{}; }; int main() { Mesh<StructuredUnstructured::kUnstructured> unstructured; Mesh<StructuredUnstructured::kStructured> structured; }

我遇到了以下错误

c++ -O3 -Wall -Wextra -Wpedantic -std=c++17 mesh_structure.cpp -o mesh_structure

奇怪的是,如果我从 mesh_structure.cpp:34:15: error: functions that differ only in their return type cannot be overloaded friend Mesh ReadMesh() {} ~~~~ ^ mesh_structure.cpp:46:45: note: in instantiation of template class 'Mesh<StructuredUnstructured::kStructured>' requested here Mesh<StructuredUnstructured::kStructured> structured; ^ mesh_structure.cpp:34:15: note: prevIoUs declaration is here friend Mesh ReadMesh() {} ~~~~ ^ mesh_structure.cpp:36:15: error: redeFinition of 'WriteMesh' friend void WriteMesh() {} ^ mesh_structure.cpp:36:15: note: prevIoUs deFinition is here mesh_structure.cpp:38:15: error: redeFinition of 'WriteMeshVTK' friend void WriteMeshVTK() {} ^ mesh_structure.cpp:38:15: note: prevIoUs deFinition is here 3 errors generated. 函数删除第二行 Mesh<StructuredUnstructured::kStructured> structured;代码会编译。我不太明白这里出了什么问题。任何帮助将不胜感激。

谢谢。

解决方法

问题不在于 std::conditional。让我们先看一个有同样问题的更简单的案例:

template <bool>
struct foo {
    friend void bar () {};
};

int main()
{
    foo<true> x;
    foo<false> y;
}

bar 被定义了两次,因此错误:

<source>: In instantiation of 'struct foo<false>':
<source>:9:16:   required from here
<source>:3:17: error: redefinition of 'void bar()'
    3 |     friend void bar () {};
      |                 ^~~
<source>:3:17: note: 'void bar()' previously declared here

要定义一次,请将定义移出模板定义:

template <bool>
struct foo {
    friend void bar ();
};

void bar() {}

int main()
{
    foo<true> x;
    foo<false> y;
}

接下来,另一个问题是您试图声明一个 Mesh<kStructured> ReadMesh() 和一个 Mesh<kUnstructured> ReadMesh()(在模板定义中,名称 Mesh 指的是 Mesh<is_structured>,除了一些特殊的案例)。

除非您将 ReadMesh 设为函数模板,否则这将不起作用。您不能仅根据返回值进行重载。一旦 ReadMesh 成为模板,您就只能像这样与匹配的特化成为朋友:

template <bool> struct foo;

template <bool x> foo<x> bar() {}

template <bool x>
struct foo {
    friend foo bar<x> ();
};

int main()
{
    foo<true> x;
    foo<false> y;
}