I want to enable a static member for a class without changing its scope.
Consider the following abstracted example:
template<uint R, uint C>
class Foo
{
static Foo ID;
/* other members */
};
Now I want to use the static member like:
Foo<3, 3> foo = Foo<3, 3>::ID;
The problem is that the ID
field can only exist when R == C
.
(Foo
is actually a Matrix
and ID
its identity which only exists for square matrices)
So I have to conditionally enable the static ID
member when the condition is met. My current solution is something like this:
struct EmptyBase { };
template<uint R, uint C>
class _Foo_Square
{
static Foo<R, C> ID;
};
template<uint R, uint C>
class Foo : public std::conditional<R == C, _Foo_Square<R, C>, EmptyBase>::type
{
/* other members */
};
But now I cannot write Foo<3, 3>::ID
to access it. I have to write _Foo_Square<3, 3>::ID
.
Unfortunately the design of my application forces it to be accessible by the Foo
class scope.
If it wasn't a conditional member I could write using _Foo_Square<3, 3>::ID;
in the Foo class.
Is there a solution to this problem?
The answer is either to fix a few bugs with your code, and/or switch to a better compiler.
After adding a proper forward declaration, and declaring the static class member as public
, the following compiles without issues with gcc 6.1.1:
#include <utility>
struct EmptyBase { };
template<int R, int C> class Foo;
template<int R, int C>
class _Foo_Square
{
public:
static Foo<R, C> ID;
};
template<int R, int C>
class Foo : public std::conditional<R == C, _Foo_Square<R, C>, EmptyBase>::type
{
/* other members */
};
void foobar()
{
Foo<3, 3> a=Foo<3, 3>::ID;
}
Simplest version I can think of:
typedef unsigned int uint;
template<uint R, uint C>
class Foo
{
//no ID here
};
template<uint R>
class Foo<R,R>
{
public:
static constexpr Foo ID = Foo();
};
int main()
{
Foo<3,3> foo1 = Foo<3,3>::ID; //ok
Foo<3,4> foo2 = Foo<3,4>::ID; //error
}
Specializing a base class Bar
you can do something like
#include <iostream>
template <std::size_t, std::size_t>
struct Foo;
template <std::size_t, std::size_t>
struct Bar
{ };
template <std::size_t N>
struct Bar<N, N>
{ static Foo<N, N> ID; };
template <std::size_t R, std::size_t C>
struct Foo : Bar<R, C>
{
// other members
};
int main ()
{
Foo<3, 3> foo = Foo<3, 3>::ID;
return 0;
}