c++11 syntax variadic templates expand with rebind - visual-c++

Is this a valid c++ syntax?
template<typename Var, typename T>
struct rebindVar;
template<typename Var, typename... T>
struct rebindVar<Var, std::tuple<T...> > {
typedef typename std::tuple< typename T::template rebindVar<Var>::type... > type;
};
Working in gcc, doesn't work in vs2013. The error message says:
Error 1 error C3546: '...' : there are no parameter packs available to expand C:\Users\Alexandros\Desktop\project\tnnlib\src\NeuralNetwork\NeuralNetwork\Perceptron\Perceptron.h 55 1 NeuralNetwork_ut

MSVC's variadic templates implementation is a huge mess, and many slightly more complex expansion patterns don't work. The usual workaround is to extract the complex part into a helper template. Try this:
template <typename Var, typename T>
struct rebindOne { typedef typename T::template rebindVar<Var>::type type; };
template<typename Var, typename... T>
struct rebindVar<Var, std::tuple<T...> > {
typedef typename std::tuple< typename rebindOne<Var, T>::type... > type;
};

Related

Why doesn't __declspec(novtable) work on a template specialization?

I have a base class for a generic callable that I'm marking __declspec(novtable):
template<class F> struct callable;
template<class R, class... T>
struct __declspec(novtable) callable<R(T...)>
{ virtual R operator()(T...) volatile { return R(); } };
but somehow this does not error like it's supposed to:
int main()
{
auto temp = new callable<void()>();
temp->operator()();
}
Why is novtable not working?
Apparently Visual C++ looks at __declspec(novtable) on the template, not its specializations!
This doesn't make sense to me (is it a bug?), but the "solution" is to write this:
template<class F> struct __declspec(novtable) callable;

C++ std::experimental::is_detected not working in MSVC

I have some code which allow a value to be converted into a string, and this works perfectly in g++ and CLion, however when I try to run the same program with MSVC in Visual Studio the program gives many errors, some of which are syntax errors which is quite odd.
This is the code I am using:
// 1- detecting if std::to_string is valid on T
template<typename T>
using std_to_string_expression = decltype(std::to_string(std::declval<T>()));
template<typename T>
constexpr bool has_std_to_string = is_detected<std_to_string_expression, T>;
// 2- detecting if to_string is valid on T
template<typename T>
using to_string_expression = decltype(to_string(std::declval<T>()));
template<typename T>
constexpr bool has_to_string = is_detected<to_string_expression, T>;
// 3- detecting if T can be sent to an ostringstream
template<typename T>
using ostringstream_expression = decltype(std::declval<std::ostringstream&>() << std::declval<T>());
template<typename T>
constexpr bool has_ostringstream = is_detected<ostringstream_expression, T>;
// -----------------------------------------------------------------------------
// 1- std::to_string is valid on T
template<typename T, typename std::enable_if<has_std_to_string<T>, int>::type = 0>
std::string toString(T const& t) {
return std::to_string(t);
}
// 2- std::to_string is not valid on T, but to_string is
template<typename T, typename std::enable_if<!has_std_to_string<T> && has_to_string<T>, int>::type = 0>
std::string toString(T const& t) {
return to_string(t);
}
// 3- neither std::string nor to_string work on T, let's stream it then
template<typename T, typename std::enable_if<!has_std_to_string<T> && !has_to_string<T> && has_ostringstream<T>, int>::type = 0>
std::string toString(T const& t) {
std::ostringstream oss;
oss << t;
return oss.str();
}
I wonder if I am doing something very obviously wrong, or if there is something a bit more complicated leading to the issue. What do I need to change in order to make this program work in Visual Studio and compile correctly?
std::experimental::is_detected is not supported in Visual Studio 2019 or earlier. You can pretty easily write your own cross platform implementation of it though, as demonstrated here: https://topanswers.xyz/cplusplus?q=1295

c++ parse from string using template

In C++, I want to get value from string.
I know there are functions like stoi, stol, stof...
But can I write a function that includes all of them? like using a template to infer the data type?
template<typename T>
T fromString(const std::string& s){
// do something here
// call stoi, stof according to typename T
}
string si = "1234";
int integer = fromString<int>(si);
string sf = "1234.1234";
float float_point = fromString<float>(sf);
Cannot comment yet, hence this ...
Not clear if you're looking for a single function, or templated (overloaded) functions? This would work: Have no default implementation with return type T, and specializations / usage so:
template<typename T> foo(const std::string& str) {}
template<> int foo(const std::string& str) {return atoi(str.c_str());}
template<> double foo(const std::string& str) {return atof(str.c_str());}
...
const std::string str1("1234"); const std::string str2("12.34");
const auto iVal = foo<int>(str1);
const auto dVal = foo<double>(str2);
Note the absence of specialization in the function name with the template function specialization, of course it appears as a return type.

Auto-interpreting a c-style string as a std::string via Boost's Property tree's .get function

I use boosts property tree, included via
#include "boost\property_tree\ptree.hpp"
And... I'd like to create a simple function which substitutes a value in case none is found via a fairly straight-forward template function:
template <typename Type>
Type getValueOrDefault( std::string const& str, Type defaultValue )
{
Type returnValue = defaultValue;
try {
returnValue = mSettings.get<Type>( str );
}
catch ( boost::property_tree::ptree_error &e )
{
// Log error!
}
return returnValue;
}
This works well in principle, but runs into a bit problems if I rely on C-style string. For example, calling the function as follows:
getValueOrDefault( "pathToImportantStuffParameter", "c:/defaultdir/" )
will result in the following error:
boost\property_tree\stream_translator.hpp(36): error C2678: binary '>>' : no operator found which takes a left-hand operand of type 'std::basic_istream<char,std::char_traits<char>>' (or there is no acceptable conversion)
The error stems from passing char const * as a template parameter which makes a fair bit of sense. Two obvious solutions to this issue would be to force the default value to be a std::string object, like so:
getValueOrDefault<std::string>( "pathToImportantStuffParameter", "c:/defaultdir/" )
getValueOrDefault( "pathToImportantStuffParameter", std::string("c:/defaultdir/") )
But I'm wondering if someone might know of some template magic I could sprinkle to automatically interpret c-style strings as std::strings?
You can provide a char array overload which converts the char array to a std::string and then calls the default implementation:
#include <iostream>
#include <string>
template <typename T>
T getValueOrDefault(const std::string& str, T&& defaultValue)
{
std::cout << "inside default implementation" << std::endl;
/* ... */
return defaultValue;
}
template <std::size_t N>
std::string getValueOrDefault(const std::string& str, const char (&defaultValue)[N])
{
std::cout << "inside char[] overload" << std::endl;
return getValueOrDefault(str, std::string(defaultValue));
}
int main()
{
auto x = getValueOrDefault("foo", "bar");
return 0;
}
live example
An alternative solution is to use custom type traits:
#include <string>
#include <type_traits>
template <typename T>
struct return_type
{
using type = T;
};
template <>
struct return_type<const char*>
{
using type = std::string;
};
template <typename T>
using return_type_t = typename return_type<typename std::decay<T>::type>::type;
template <typename T>
return_type_t<T> getValueOrDefault(const std::string& str, T&& defaultValue)
{
return_type_t<T> value(defaultValue);
/* ... */
return value;
}
int main()
{
auto x = getValueOrDefault("foo", "bar");
static_assert(std::is_same<decltype(x), std::string>::value, "");
return 0;
}
live example
The only way I found is to specialize getValueOrDefault for const char*, which calls getValueOrDefault with std::string explicitly:
//Note that the return value is unspecified, it returns a 'const char*' to a temporary,
//which will be destroyed when the function returns
template <>
const char* getValueOrDefault(std::string const& str, const char* defaultValue)
{
return getValueOrDefault<std::string>(str, defaultValue).c_str();
}
If you want to that function to return a std::string instead of an invalid const char*, you have to change the template signature a bit:
//Default return type is the same as paramter
template <typename Type, typename Return = Type>
Return getValueOrDefault(std::string const& str, Type defaultValue)
{
//...
}
//Trick the compiler to select this overload for 'const char*'
template <typename Return = std::string>
Return getValueOrDefault(std::string const& str, const char* defaultValue)
{
return getValueOrDefault<std::string, std::string>(str, defaultValue);
}
or you could just plain overload the function (thanks #m.s.)
//Overload for 'const char*'
std::string getValueOrDefault(std::string const& str, const char* defaultValue)
{
return getValueOrDefault<std::string>(str, defaultValue);
}
There is also a third way (if you can use C++14), using the string literal ""s:
//"c:/defaultdir/"s is a std::string (note the s after it => string literal)
getValueOrDefault("pathToImportantStuffParameter", "c:/defaultdir/"s);

MSVC++ Compiler Error C2892?

int main() {
struct local {
template<class T> // This line generates C2892 error.
void f() {}
};
}
Why I cannot use template member in local classes and structures? What causes such restrictions in Visual C++?
C++03 14.5.2/2 "Member templates" says:
A local class shall not have member templates
(same in C++98 and C++11). I don't know what the rationale is.

Resources