Reputation: 558
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
Reputation: 45664
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
).
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)>;
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