Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Idiomatic Type Traits

Tags:

c++

typetraits

I have a system of type traits that resides in a namespace, like so:

namespace my_namespace
{

template <typename T>
struct magic_traits
{
    static const int value = 0;
};

}

Because people hate the syntax of template specializations, I have this convenient little macro:

#define DECLARE_MY_MAGIC_TRAITS(type_, value_) \
    namespace my_namespace                     \
    {                                          \
        template <>                            \
        struct magic_traits<type_ > {          \
            static const int value = value_;   \
        };                                     \
    }

}

My problem is that this only works for declarations made in the global namespace, so traits for a type in some other namespace looks like this:

DECLARE_MAGIC_TRAITS(other_namespace::some_type, 9)

That's great, if people know about all the little namespace rules about where DECLARE_MAGIC_TRAITS belongs. If they don't and put the declaration in their own namespace, they'll get errors like:

'magic_traits' is not a template!
Specialization of non-template 'other_namespace::my_namespace::magic_traits'

Which are quite confusing to a new user of your library!

Is there a way to make that macro be able to define a specialization of magic_traits from anywhere? If that is not possible (as I suspect): What techniques can be used to generate more reasonable error messages?

I should note that my users are mostly Python programmers and have very little C++ experience, so anything I can do to make their lives easier, the better.

like image 655
Travis Gockel Avatar asked Jul 04 '11 15:07

Travis Gockel


2 Answers

Maybe a bit ugly, but how about this as an idea :

namespace my_namespace
{

typedef bool The_DECLARE_MY_MAGIC_TRAITS_macro_should_be_used_in_the_global_namespace;

template <typename T>
struct magic_traits
{
    static const int value = 0;
};

}

#define DECLARE_MY_MAGIC_TRAITS(type_, value_) \
    namespace my_namespace {                   \
        typedef The_DECLARE_MY_MAGIC_TRAITS_macro_should_be_used_in_the_global_namespace CheckPrecondition; \
        template <>                            \
        struct magic_traits<type_ > {          \
            static const int value = value_;   \
        };                                     \
    }

When the macro is used incorrectly, it would generate an error such as this :

error: ‘The_DECLARE_MY_MAGIC_TRAITS_macro_should_be_used_in_the_global_namespace’ does not name a type
error: ‘magic_traits’ is not a template
error: explicit specialization of non-template ‘other_namespace::my_namespace::magic_traits’

That might give enough of a hint as to what's wrong.

like image 106
Sander De Dycker Avatar answered Oct 17 '22 03:10

Sander De Dycker


There is probaly nothing better than good documentation.

You should tell the users of your DECLARE_MAGIC_TRAITS macro where to put the macro, and what to write inside the parameters (with examples)

And make the error messages a faq entry so that users will find a good answer to what went wrong.

like image 35
Fabio Fracassi Avatar answered Oct 17 '22 04:10

Fabio Fracassi