I. Abandon overloading
the two logAndAdd overloads could be broken into logAndAddName and logAndAddNameIdx
II. Pass by const T&
std::multiset<std::string> names;
void logAndAdd(const std::string& name) {
auto now = std::chrono::system_clock::now();
log(now, "logAndAdd");
names.emplace(name);
}
void logAndAdd(int idx);
because name is an lvalue, it is copied into names.
std::multiset<std::string> names;
template<typename T>
void logAndAdd(T&& name) {
auto now = std::chrono::system_clock::now();
log(now, "logAndAdd");
names.emplace(std::forward<T>(name));
}
void logAndAdd(int idx);
short nameIdx;
logAndAdd(nameIdx); // error
III. Pass by value
class Person {
public:
explicit Person (std::string n) : name(std::move(n)) { }
explicit Person (int idx) : name(nameFromIdx(idx)) { }
private:
std::string name;
};
IV. Use tag dispatch
std::mulitset<std::string> names;
tmplate<typename T>
void logAndAdd(T&& name) {
logAndAddImpl(std::forward<T>(name), std::is_integral<typename std::remove_reference<T>::type>());
}
template<typename T>
void logAndAddImpl(T&& name, std::false_type) {
auto now = std::chrono::system_clock::now();
log(now, "logAndAdd");
names.emplace(std::forward<T>(name));
}
std::string nameFromIdx(int idx);
vid logAndAdd(int idx, std::true_type) {
logAndAdd(nameFromIdx(idx));
}
V. Constraining templates that take universal references
class Person {
public:
template<typename T, typename = std::enable_if_t<
!std::is_base_of<Person, std::decy_t<T>>::value // avoid copy Person object
&&
!std::is_integral<std::remove_reference_t<T>>::value
>
>
explicit Person(T&& n): name(std::forward<T>(n)) {... }
explicit Person(int idx):name(nameFromIdx(idx)) { ... }
...
private:
std::string name;
};