From: Johannes Schaub (litb) on
Cory Nelson wrote:

> Hello all,
>
> I am using CRTP (the Curiously Recurring Template Pattern) like so:
>
> template<T>
> struct base
> {
> void do_something()
> {
> prepare();
> static_cast<T*>(this)->hide_me();
> finalize();
> }
>
> void hide_me() {}
> };
>
> struct derived : base<derived>
> {
> void hide_me() { /* do something else */ }
> };
>
> I have a lot of these hideable functions, and different types of T
> need to hide different functions. In this situation, it would be more
> efficient to simply not do the prepare() or finalize() stage if these
> functions are not implemented in the derived type.
>
> So I'd like to find a way to detect if a function is hidden or not, in
> a way that works at compile-time so that I can use it with templates
> to prevent the prepare() or finalize() code from even being
> instantiated. Does anyone have any ideas?
>

Assuming that the derived class implements a fixed interface. The sizeof
works at compile time. The below is a simple example that is not entirely
compile time, of course:

template<typename T>
struct base
{
template<typename F>
static identity<char[1]>::type &check(F base::*);
template<typename F>
static identity<char[2]>::type &check(F T::*);

void do_something()
{
if(sizeof check<void()>(&T::hide_me) == 2)
prepare();
static_cast<T*>(this)->hide_me();
if(sizeof check<void()>(&T::hide_me) == 2)
finalize();
}

void hide_me() { return unimplemented(); }
};

struct derived : base<derived>
{
void hide_me() { /* do something else */ }
};

Notice that because of a restriction in the Standard, compilers will reject
"void()const". You will have to write "typedef void ft() const;
check<ft>(....)" to check a const member function.

But even then, at least one compiler (remarkable, Comeau/EDG) rejects it. I
think tho that the issue is not all that clear. The Standard forbids a cv-
qualifier-seq like "void()const" except when nested in a member pointer,
when used for declaring class member functions or in a typedef. In my
opinion, the Standard is not sufficiently clear whether this is a lexical
rule (i.e that one merely cannot write "void()const"), or a semantical rule
(that a type cannot be denoted if not by a typedef-name (in C++03 "F" above
will violate such a requirement), or implicitly as part of a member pointer,
etc). For the logs: clang accepts the code: It apparently interprets it
lexically, while comeau interprets it semantically.

In any case, to summarize: It won't work portably with const member
functions.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Gert-Jan de Vos on
On Feb 16, 7:09 am, Cory Nelson <phro...(a)gmail.com> wrote:
> Hello all,
>
> I am using CRTP (the Curiously Recurring Template Pattern) like so:
>
> template<T>
> struct base
> {
> void do_something()
> {
> prepare();
> static_cast<T*>(this)->hide_me();
> finalize();
> }
>
> void hide_me() {}
>
> };
>
> struct derived : base<derived>
> {
> void hide_me() { /* do something else */ }
>
> };
>
> I have a lot of these hideable functions, and different types of T
> need to hide different functions. In this situation, it would be more
> efficient to simply not do the prepare() or finalize() stage if these
> functions are not implemented in the derived type.
>
> So I'd like to find a way to detect if a function is hidden or not, in
> a way that works at compile-time so that I can use it with templates
> to prevent the prepare() or finalize() code from even being
> instantiated. Does anyone have any ideas?

You can try to match a T::hide_me member function pointer with both
void (base::*)() and void (T::*)(). If T::hide_me is not defined, then
it will match void (base::*)().

#include <iostream>

template <typename T>
struct base
{
void do_something()
{
do_something(&T::hide_me);
}

void do_something(void (base::*)())
{
// There is no T::hide_me, do nothing..
}

void do_something(void (T::*)())
{
prepare();
static_cast<T*>(this)->hide_me();
finalize();
}

void prepare() { std::cout << "prepare()\n"; }
void finalize() { std::cout << "finalize()\n"; }

void hide_me() {}
};

struct derived1 : base<derived1>
{
void hide_me() { /* do something else */ }
};

struct derived2 : base<derived2>
{
};

int main()
{
std::cout << "derived1\n";
derived1 d1;
d1.do_something();

std::cout << "derived2\n";
derived2 d2;
d2.do_something();
}


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]