【问题标题】:Issue with using std::conditional in a template class在模板类中使用 std::conditional 的问题
【发布时间】:2021-09-30 10:48:54
【问题描述】:

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

下面是 MWE。在这个 MWE 中,我试图根据条件分别为真(结构化)或假(非结构化)来创建模板类 Mesh 的成员 FiniteElementListstd::vectorstd::listMesh 类包含一些成员和友元函数,这些函数只是暂时声明的,可能会在以后定义。

MWE

// 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;
}

编译:

我正在尝试使用 clang 编译器编译如下

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.

很奇怪,如果我从main() 函数中删除第二行Mesh&lt;StructuredUnstructured::kStructured&gt; structured;,代码就会编译。我不太明白这里出了什么问题。任何帮助将不胜感激。

谢谢。

【问题讨论】:

  • 将为类模板的每个实例定义相同的免费friend 函数。他们不应该也依赖于非类型模板参数吗?由于功能不完整,很难确切说明如何。

标签: c++ templates conditional-statements c++17 static-polymorphism


【解决方案1】:

问题不在于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&lt;kStructured&gt; ReadMesh() 和一个Mesh&lt;kUnstructured&gt; ReadMesh()(在模板定义中,名称Mesh 指的是Mesh&lt;is_structured&gt;,除了一些特殊情况)。

除非您将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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-27
    • 1970-01-01
    • 1970-01-01
    • 2014-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多