I am trying to define a template class with non-type template parameter. I then determine the type of the member of this class from this template parameter using std::conditional. I am running into some compile time errors.
Below is the MWE. In this MWE, I am trying to make the member, FiniteElementList, of template class, Mesh, either std::vector or std::list based on the condition being true (structured) or false (unstructured) respectively. The class, Mesh, contains some member and friend functions that are only declared for the moment and might be defined at a later stage.
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;
}
Compilation:
I am trying to compile with clang compiler as follows
c++ -O3 -Wall -Wextra -Wpedantic -std=c++17 mesh_structure.cpp -o mesh_structure
And I run into the following errors
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.
Strange enough, the code compiles if I remove the second line, Mesh<StructuredUnstructured::kStructured> structured;, from main() function. I don't quite get what went wrong here. Any help would be greatly appreciated.
Thank you.
The issue is not with
std::conditional. Lets first look at a much simpler case with same problem:baris defined twice, hence the error:To define it once, move the definition out of the templates definition:
Next, another issue is that you are trying to declare a
Mesh<kStructured> ReadMesh()and aMesh<kUnstructured> ReadMesh()(within the template definition the nameMeshrefers toMesh<is_structured>, except some special cases).Thats not going to work unless you make
ReadMesha function template. You cannot overload based on return value alone. OnceReadMeshis a template, you can befriend only the matching specialization like this: