Enabling a static member conditionally without cha

2019-07-26 21:55发布

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?

3条回答
神经病院院长
2楼-- · 2019-07-26 22:15

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
}
查看更多
欢心
3楼-- · 2019-07-26 22:21

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;
}
查看更多
老娘就宠你
4楼-- · 2019-07-26 22:32

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;
 }
查看更多
登录 后发表回答