Reputation: 39
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.
Upvotes: 1
Views: 266
Reputation: 122585
The issue is not with std::conditional
. Lets first look at a much simpler case with same problem:
template <bool>
struct foo {
friend void bar () {};
};
int main()
{
foo<true> x;
foo<false> y;
}
bar
is defined twice, hence the error:
<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
To define it once, move the definition out of the templates definition:
template <bool>
struct foo {
friend void bar ();
};
void bar() {}
int main()
{
foo<true> x;
foo<false> y;
}
Next, another issue is that you are trying to declare a Mesh<kStructured> ReadMesh()
and a Mesh<kUnstructured> ReadMesh()
(within the template definition the name Mesh
refers to Mesh<is_structured>
, except some special cases).
Thats not going to work unless you make ReadMesh
a function template. You cannot overload based on return value alone. Once ReadMesh
is a template, you can befriend only the matching specialization like this:
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;
}
Upvotes: 4