Nick Nick - 2 months ago 15
C++ Question

template const / non const method

Suppose we have code like this:

template<class CALLBACK>
struct INIFile{
INIFile(CALLBACK &processor) :
processor(processor ){}

bool process(){
// lots of code here,
// call processor
processor(123);

return true;
}

CALLBACK &processor;
};


struct MyProcessor{
void operator()(int val){
// do something
}
};

struct MyConstProcessor{
void operator()(int val) const{ // !!!!!
// do something
}
};

int main(){
MyProcessor p;
INIFile<MyProcessor> ini(p);
ini.process();

// const case:
MyConstProcessor cp;
INIFile<MyConstProcessor> cini(cp);
cini.process();
}


In both cases
INIFile<>::process()
will be a non
const
member function.

Is there an easy way to make
process()
a
const
member function if
CALLBACK::operator()
is
const
, without duplicate all logic in
INIFile<>::process()
?

Answer Source

Is there an easy way to make process() a const member function if CALLBACK::operator() is const, without duplicate all logic in INIFile<>::process()?

I don't think so.

If (but only if) your "lot of code" is a lot of const code, the best I can imagine is put that code in a const method and define process() in const and not const version.

void lotOfConstCode () const
 { /* lot of const code here */ }

bool process () const
 {
   lotOfConstCode();

   processor(123);

   return true;
 }

bool process ()
 {
   lotOfConstCode();

   processor(123);

   return true;
 }

If you really don't want that you INIFile struct define, at the same time, the two process() versions (but why?), you can SFINAE enable/disable they.

Just for fun, I propose a full working example

#include <utility>
#include <iostream>
#include <type_traits>

template <typename>
constexpr bool withOpIntConstHelper (long)
 { return false; }

template <typename T>
constexpr auto withOpIntConstHelper (int)
   -> decltype(std::declval<T const>()(0), bool{})
 { return true; }

template <typename T>
constexpr bool withOpIntConst ()
 { return withOpIntConstHelper<T>(0); }


template <typename CB>
struct iniFile
 {
   iniFile (CB & p0) : processor(p0)
    { }

   void lotOfConstCode () const
    { }

   template <typename T = CB>
   typename std::enable_if<(true == std::is_same<T, CB>::value)
                        && (true == withOpIntConst<CB>()), bool>::type
         process () const
    {
      std::cout << "process const version" << std::endl;

      lotOfConstCode();

      processor(123);

      return true;
    }

   template <typename T = CB>
   typename std::enable_if<(true == std::is_same<T, CB>::value)
                        && (false == withOpIntConst<CB>()), bool>::type
         process ()
    {
      std::cout << "process not const version" << std::endl;

      lotOfConstCode();

      processor(123);

      return true;
    }

   CB & processor;
 };


struct mP
 { void operator() (int val) { } };

struct mCP
 { void operator() (int val) const { } }; 

int main ()
 {
   static_assert( false == withOpIntConst<mP>() , "!" );
   static_assert( true == withOpIntConst<mCP>() , "!" );

   mP p;
   iniFile<mP> ini(p);
   ini.process();

   // const case:
   mCP cp;
   iniFile<mCP> cini(cp);
   cini.process();
 }