user1493321
user1493321

Reputation:

Conditional cv qualifier in function

I would like to make a method conditionally const. That is, we have

template <bool isConst>
class A {
    // stuff
};

depending on the value of the template parameter, either

void method() const;

or

void method();

appear in the body of A.

My first thought was to try conditional types, but this does not work, for obvious reasons.

Upvotes: 1

Views: 167

Answers (2)

qeadz
qeadz

Reputation: 1516

EDIT: This is only intended for interests' sake. I don't suggest actually doing this in a commercial product. Maybe in a personal project if you're trying out things.

Something you could do, which is a little hacky, is this:

template< bool OnlyConst >
class TestClass
{
  struct Placeholder {};
public:

  template< class T >
  typename std::enable_if< OnlyConst && !std::is_same<T, Placeholder>::value, void >::type 
    MyFunc() const 
  { std::cout << "Const version"; }

  template< class T >
  typename std::enable_if< !OnlyConst && !std::is_same<T, Placeholder>::value, void >::type 
    MyFunc() 
  { std::cout << "Nonconst version"; }
};

The unfortunate bit is that the functions do need to be templated to use the enable_if, and if you have nothing to do with that template then the caller is still going to need to provide it so the compiler can 'use' it. You can't use a default template parameter for T either.

If you could find a use for T that would let the compiler automatically determine its type then it would work out well.

Right now you'd have to always give a value for T when calling:

test.MyFunc<void>(); // even though the void doesn't affect it at all

The placeholder struct is only there because SFINAE (at least on VS2012) seems to want T to be part of the determination of whether the function can be instantiated or not. So the is_same call is pretty much just for sticking some usage of T in the enable_if.

I have done a spot of testing with the above code in VS2012 and it seems to work.

Upvotes: 1

Daniel Frey
Daniel Frey

Reputation: 56883

The obvious solution is a specialization:

template<bool>
struct A
{
    void method() const
    {
        std::cout << "const" << std::endl;
    }
};

template<>
struct A<false>
{
    void method()
    {
        std::cout << "non-const" << std::endl;
    }
};

and in case you have more methods and don't want to duplicate them, make A a base class A_base and derive your A from it. (I added this to the live example below)

Live example

Upvotes: 2

Related Questions