Below is a minimal code which compiles in g++, but gives error in MSVC:
template<typename Type,
typename Return, // <--- error: this is not deduced
typename Container,
typename Parameter>
Container
StringTo (Type&& copy,
const char tokens[],
Return (Container::*Insert) (const Parameter&))
{
static_assert(not std::is_lvalue_reference<Type>::value, "Must be rvalue.");
Container container;
return container;
}
template<typename Type>
auto
StringToVector (Type&& copy,
const char tokens[])
{
static_assert(not std::is_lvalue_reference<Type>::value, "Must be rvalue.");
return StringTo(std::move(copy), tokens, &std::vector<Type>::push_back); // <--- here
}
int main()
{
auto v = StringToVector(std::string("hello world"), " ");
}
As per this post, it's a bug in MSVC which is not yet fixed: Visual Studio 2017 - could not deduce template argument (with variadic templates)
Question: What is the workaround to fix it for this specific case?
Update: This bug isn't fixable, & I am open to changing of design/interface. You are welcome to post it as an answer. Will accept the best one.
By adding the container type you want to the template parameter list of StringTo and then taking the function as a generic type allows you to use a lambda in StringToVector to forward to the correct member function. That would look like
template<typename Container,
typename Type,
typename Func>
Container
StringTo (Type&& copy,
const char tokens[],
Func func)
{
static_assert(not std::is_lvalue_reference<Type>::value, "Must be rvalue.");
Container container;
func(container, std::move(copy));
return container;
}
template<typename Type>
auto
StringToVector (Type&& copy,
const char tokens[])
{
static_assert(not std::is_lvalue_reference<Type>::value, "Must be rvalue.");
return StringTo<std::vector<Type>>(std::move(copy), tokens, [](auto& cont, auto&& val){ cont.push_back(std::move(val)); } ); // <--- here
}
int main()
{
auto v = StringToVector(std::string("hello world"), " ");
}
And you can see it working on Rextester here: https://rextester.com/BLSS95194
A more lean design might just do:
template<typename Type>
auto
StringToVector (Type&& copy,
const char tokens[])//what are we going to use this for ?
{
return std::vector{ copy };
}
Try it yourself on godbolt
Would that be a usable work-around ?
Another approach could be to use a type based customization design from the get-go
instead (example using std::back_insert_iterator)
#include <utility>
#include <string>
#include <vector>
template<typename Container,
typename Inserter,
typename Type
>
Container
StringTo (Type&& copy,
const char tokens[])
{
static_assert(!std::is_lvalue_reference<Type>::value, "Must be rvalue.");
Container container;
*Inserter(container) = copy;
return container;
}
template<typename Type>
auto
StringToVector (Type&& copy,
const char tokens[])
{
static_assert(!std::is_lvalue_reference<Type>::value, "Must be rvalue.");
return StringTo<std::vector<Type>, std::back_insert_iterator<std::vector<Type> > >(std::move(copy), tokens);
}
int main()
{
auto v = StringToVector(std::string("hello world"), " ");
}
Try it yourself
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With