On Fri, Jul 20, 2012 at 10:52 AM, Brian Budge <brian.budge@gmail.com> wrote:
Hi all -

I am hoping to define my own type trait is_memcpyable.

I'm trying to start off simple:

template <typename T>
struct is_memcpyable {
    static const bool value = boost::has_trivial_assign<T>::value;
};

Then when I encounter types in my code that are safe to memcpy, but
don't have a trivial assignment operator I can specialize the trait.

I'm having trouble with inheritance and composition.  I'm hoping
someone can help.  Here's a complete code sample:

/***START OF SAMPLE***/
#include <Eigen/Dense>
#include <iostream>

template <typename T>
struct is_memcpyable {
    static const bool value = boost::has_trivial_assign<T>::value;
};


namespace boost {
    template<>
    struct has_trivial_assign<Eigen::Vector3f> : public true_type {};
}


struct foo : public Eigen::Vector3f {

    foo() {}

};

struct bar {
    bar(int i) : m_vec(float(i), float(i), float(i)) {}

    Eigen::Vector3f m_vec;
};


int main(int argc, char **args) {

    std::cerr << "memcpyable int: " << is_memcpyable<int>::value << std::endl;
    std::cerr << "memcpyable v3f: " <<
is_memcpyable<Eigen::Vector3f>::value << std::endl;
    std::cerr << "memcpyable bar: " << is_memcpyable<bar>::value << std::endl;
    std::cerr << "memcpyable foo: " << is_memcpyable<foo>::value << std::endl;

    std::cerr << "trivial assign int: " <<
boost::has_trivial_assign<int>::value << std::endl;
    std::cerr << "trivial assign v3f: " <<
boost::has_trivial_assign<Eigen::Vector3f>::value << std::endl;
    std::cerr << "trivial assign bar: " <<
boost::has_trivial_assign<bar>::value << std::endl;
    std::cerr << "trivial assign foo: " <<
boost::has_trivial_assign<foo>::value << std::endl;

    return 0;
}
/***END OF SAMPLE***/

The Eigen library is set up to do nifty expression template goodness
all over the place, which means that they implement operator = for the
types in the library.  However, once a value is assigned, the storage
is fixed (at least for the Dense matrix types).   The data layout is
fixed, and internal storage is a small array of builtin types.

What I would like to happen is that all 8 print statements should be
true; however, the ones for bar and foo are false.  I can explicitly
set their type traits, but this quickly gets out of hand.

I guess the real question is this:  is there a way to define
is_memcpyable so that the value is true if a class does not define
operator=, and all of it's members or inherited types are also
memcpyable?

As Steven said, no, but one thing that may minimize the boilerplate is for the default implementation to detect whether a specific typedef is present (e.g., is_memcpyable_tag), and, if so, use T::is_memcpyable_tag::value for the value of is_memcpyable<T>::value. Then write a macro that typedef's is_memcpyable_tag given a set of base and member objects, which makes your class definitions something like

struct foo : public Eigen::Vector3f
{
    TYPEDEF_IS_MEMCPYABLE_TAG( ( Eigen::Vector3f ) )
};

struct bar
{
    TYPEDEF_IS_MEMCPYABLE_TAG( ( Eigen::Vector3f ) ( X ) )

    Eigen::Vector3f m_vec;
    X some_member;
};

This is something maybe to consider, anyway.

- Jeff