Using std::decay with std::forward

Viewed 215
template<typename T>
struct test
{
    std::string key;
    T value;
    
    template<typename U>
    using decay = typename std::decay<U>::type;

    template<typename U = decay<T>, typename US = decay<std::string>>
    test(U&& _value, US&& _key) : value(std::forward<U>(_value)), key(std::forward<US>(_key)){}
};

I use decay like this in my almost every project. I want ask, if its a good use instead, of writing something like this :

test(T&& _value, std::string&& _key) : value(std::move(_value)), key(std::move(_key)){}
test(const T& _value, std::string&& _key) : value(_value), key(std::move(_key)){}
test(T&& _value, const std::string& _key) : value(std::move(_value)), key(_key){}
test(const T& _value, const std::string& _key) : value(_value), key(_key){}
2 Answers

You overthink this. You need just this:

template<typename T>
struct test
{
    std::string key;
    T value; // as a safety this could be replaced by:
    // typename std::decay<T>::type value;
    
    template<typename U, typename US>
    test(U&& _value, US&& _key)
       : value(std::forward<U>(_value))
       , key(std::forward<US>(_key))
    {}
};

This perfect forwarding will ensure that all constructors you have listed are available.

Looks like you do not understand what std::decay do, or when/how to use it. Example: decay<std::string> is pointless, since this just represents std::string type, so you should write just std::string you do not have to do any conversion since you have full control over type passed to decay, you know this type doesn't contain reference or const since you have type this explicitly.

std::decay is useful to define a variable/filed of type which you could assign to. It strips references and constness, C-array converts to pointer, and ensures pointer to functions. See doc example.

Could you explain what was your plan to achieve with this default types for template parameters? I can't figure out what was your intention here.

If both values are actually kept inside your class, it is much simpler than that:

test(T value, std::string key)
    : value(std::forward<T>(value)), key(std::move(key)) {}
Related