Search code examples
c++templatesvariadic-templates

Cast from type parametrized by const template argument to non-const template argument


I have a class with variadic template parameters:

template<typename... Args>
class something {
public:
  something(Args&&... args); // omitted for brevity
}

I have a function that accepts a list of arguments and returns an object of this class:

template<typename... Args>
auto make_something(Args&&... args) {
    return something<Args...>(std::forward<Args>(args)...);
}

If I call it like so:

something<int, std::string> s = make_something<int, std::string>(1, "");

it compiles and works fine.

but if I try to pass a const argument, I get compile errors:

const std::string t = "";
something<int, std::string> s1 = make_something(1, t); // no viable conversion from something<... const basic_string<char>> to something<... std::string>

How can I successfully pass const and then, idk, cast the result to the requested type, parametrized by a non-const type?

I suspect it has something to do with the type of the object I'm returning but I don't actually know what to replace auto with in this case.


Solution

  • There are two options, depending on if you really want to have something<int, const std::string &> be a type that make_something(1, t) returns.

    If that is the case, you can have a converting constructor

    template<typename... Args>
    class something {
    public:
      something(Args&&... args); // omitted for brevity
      template<typename... OtherArgs> 
      something(something<OtherArgs...>); // convert each OtherArgs into Args
    }
    

    In the alternative, where you want make_something(1, t) to result in something<int, std::string>

    template<typename... Args>
    class something {
    public:
      template<typename... OtherArgs> 
      something(OtherArgs&&...); // use each OtherArgs for Args
    }
    
    template <typename... Args>
    auto make_something(Args&&... args)
    {
        return something<std::decay_t<Args>...>(std::forward<Args>(args)...);
    }