Fourmet
Fourmet

Reputation: 558

When to pass by copy / reference?

Say I have two templates for an operator= overloading :

class MyClass {
public:
    template <typename T>
    std::enable_if_t<true == /* a condition */, MyClass&>
    operator=(T value) {
        std::cout << "Pass by copy" << std::endl;
    }

    template <typename T>
    std::enable_if_t<false == /* a condition */, MyClass&>
    operator=(const T &value) {
        std::cout << "Pass by reference" << std::endl;
    }
};

What would be the most optimal condition to use with std::enable_if ?

I came up with this :

template <typename T>
struct pass_copy_cond : std::conditional<
        std::is_fundamental<T>::value ||
        std::is_pointer<T>::value ||
        (std::is_trivial<T>::value && sizeof(T) < sizeof(void*))
    , std::true_type, std::false_type>::type {};

Is there a way to improve the condition ?

Upvotes: 4

Views: 153

Answers (1)

Deduplicator
Deduplicator

Reputation: 45664

Some checks are redundant:

All fundamental types and pointer types are also trivial. Admittedly, some fundamental types could be bigger than void* (pointers to member / member function, though they are likely larger, are not detected by std::is_pointer).

This is over-constraining:

Being trivially copyable is enough, trivial default-constructibility is irrelevant. One might even make a case for trivial destructibility alone to be sufficient.

template <class T>
using prefer_copy = std::bool_constant<std::is_trivially_copyable<T>() && sizeof(T) <= sizeof(std::max_align_t)>;

You will be writing the implementation twice

If your compiler allows you to force inlining (not standardised, but nearly every compiler allows it somehow), you can delegate to that singular common implementation and get it inlined.

Upvotes: 1

Related Questions