1

I want to be able to make the compiler shout when i call a constructor of foo with a class that is NOT derived from _base*. The current code allows only for foo<_base*> itself. Any easy solution ?

class _base
{
public:
    // ...
};

class _derived: public _base
{
public:
    // ...
};

template <typename T>
class foo
{
public:
    foo ()      { void TEMPLATE_ERROR; }
};

template <> foo<_base*>::foo () 
{
    // this is the only constructor
}

main-code:

foo<_base*>    a;    // should work 
foo<_derived*> b;    // should work (but doesnt)
foo<int*>      c;    // should not work (and infact doesnt)
Roman Pfneudl
  • 707
  • 1
  • 8
  • 21

3 Answers3

4

Use SFINAE (via enable_if) and Boost’s is_convertible type trait:

template <typename T, typename Enabled = void>
class foo
{
private:
    foo(); // Constructor declared private and not implemented.
};

template <typename T>
class foo<T, typename enable_if<is_convertible<T, _base*> >::type>
{
public:
    foo() { /* regular code */ }
};

(untested, haven’t got Boost installed on this machine.)

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • Thanx, i read through the links and they triggered some thoughts. Should be a good solution, but im not using boost so far. – Roman Pfneudl Nov 01 '09 at 18:33
  • The beauty of Boost is that you can use only parts of it – in particular, most headers can just be copy-pasted in either your project’s directory or a system include directory. – Konrad Rudolph Nov 01 '09 at 21:10
3

Without Boost you can use something like the following to determine whether a pointer-to-type can be implicitly cast to another pointer-to-type:

template <class Derived, class Base>
struct IsConvertible
{
    template <class T>
    static char test(T*);

    template <class T>
    static double test(...);

    static const bool value = sizeof(test<Base>(static_cast<Derived*>(0))) == 1;
};

To make it trigger an error at compile-time, you can now use value in an expression that causes an error if it is false, for example typedef a negative-sized array.

template <typename T>
class foo
{
public:
    foo ()
    {
        typedef T assert_at_compile_time[IsConvertible<T, _base>::value ? 1 : -1];
    }
};
UncleBens
  • 40,819
  • 6
  • 57
  • 90
  • aaah, thank you. i tried to figure that out by myself diving into the boost-djungle, but i stumbled about alot of code-tangleweed so i had to retreat. But this is, exactly what i'm searching for, thank you. – Roman Pfneudl Nov 02 '09 at 08:28
  • 1
    I recommend you reading "Modern C++ Design: Generic Programming and Design Patterns Applied" by Andrei Alexandrescu if you want to learn more Template-related techniques like this one. – Julien-L Nov 02 '09 at 14:59
  • +1 That's a really good one. And thanks for the book recommendation! – Diego Sevilla Nov 03 '09 at 00:30
1

I understand that you are not using boost in your project, but maybe you could copy-paste some parts of it.

I found a simpler solution to your problem using boost:

template <typename T>
class foo
{
public:
    foo () {
        BOOST_STATIC_ASSERT((boost::is_convertible<T,_base*>::value));
    }
};

It doesn't require additional template parameter, also no need for template specialization. I tested it with boost 1.40.

parti3an
  • 137
  • 3