3

Let's say I have a C++ class template:

template <class _T>
class MyClass
{
public:
    int func();

private:
    _T internal;
};

I'd like a way to specify a boolean to this template that, when true, will make every member in this template public.

For example:

MyClass<SomeClass, false> c1;
c1.internal.someFunc(); // ERROR

MyClass<SomeOtherClass, true> c2;
c2.internal.someFunc(); // SUCCESS

For those wondering, I'm using gtest and gmock to mock up concrete classes. So, in one of my unit tests I will have something like:

TEST(MyClass, Test1) {
    MyClass<SomeMockClass, true> c1;
    EXPECT_CALL(c1.internal, someFunc()).Times(1);
}

For this test template, internal must be accessible by my code. In production, I'd like to hide that from the user.

I'm using msvc 11 (Visual Studio 2012), so I have access to some C++11 features and metaprogramming constructs.

jmacdonagh
  • 3,851
  • 3
  • 18
  • 14
  • 4
    `_T` is definitely not a good name to use. It's reserved for the implementation, and this one especially, as I know it's in use as a macro to widen a string based on whether your program is using wide-character stuff or not. – chris Sep 11 '12 at 02:09
  • Good tip @chris. I did this as an example and I'm almost much more specific in my templates, but that's good to know. – jmacdonagh Sep 11 '12 at 02:16
  • 1
    If you're interested, http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier – chris Sep 11 '12 at 02:24

2 Answers2

4

You can inherit a test helper from the main class, helper that you declare friend, and then promote the elements that you are interested in public:

#include <iostream>

template<typename T> class TestMyClass;

template<typename T>
class MyClass
{
    friend class TestMyClass<T>;
    public:
        int func();
    private:
        T internal;
};

template <class T>
class TestMyClass : public MyClass<T>
{
    public:
        using MyClass<T>::internal;
};

int main()
{
    TestMyClass<double> s;
    s.internal = 5;
    std::cout << s.internal << "\n";
    return 0;
}
sylvain.joyeux
  • 1,659
  • 11
  • 14
  • This is a pretty close answer to the solution I went with. I had just started to use GoogleTest and ran into the issue of private members. I didn't realize they already provided a solution: http://code.google.com/p/googletest/wiki/AdvancedGuide#Private_Class_Members – jmacdonagh Sep 13 '12 at 13:56
1

You can do this with class template specialization, however, it does mean you need to modify both sets of code when you make a change:

#include <iostream>

template <class T, bool visible>
class MyClass
{
};

template <class T>
class MyClass<T, true>
{
public:
    int func();
    T internal;
};

template <class T>
class MyClass<T, false>
{
public:
    int func();
private:
    T internal;
};

int main()
{
    MyClass<int, true> s;
    s.internal = 5;
    std::cout << s.internal << "\n";
    return 0;
}
Yuushi
  • 25,132
  • 7
  • 63
  • 81