Passing function with defaults as argument ignoring them - c++

I need to convert a string that represents a vector of Ts into the corresponding vector.
My problem is that I'd like to pass a simple argument: the converter function. Here's the split:
template <class T>
auto split(const std::string &s, const std::function<T(const std::string&)> &convert, char sep = ',') -> std::vector<T>
{
std::stringstream ss(s);
std::vector<T> result;
while (ss.good())
{
std::string substr;
std::getline(ss, substr, sep);
if (!substr.empty())
result.push_back(convert(substr));
}
return result;
};
It fails to compile when passing standard functions such as std::stoi because of the default parameters of std::stoi as its signature is int stoi(const string& __str, size_t* __idx = 0, int __base = 10);:
auto q = split<int>(subs, std::stoi);
error: no matching function for call to 'split'
auto q = split<int>(subs, std::stoi);
^~~~~~~~~~
And obviously I can trick the compiler by using a lambda function:
auto q = split<std::size_t>(subs, [](const std::string &s){ return std::stoul(s); });
Is there a metaprogramming trick that allows me to somehow ignore the default parameters?

EDIT: This doesn’t actually help in this case. I’m leaving it because it’s useful in some other cases, such as if you had a function which returned something convertible to T, but it doesn’t address any of the issues with stoi.
Don’t explicitly specify the type of the function. Let convert be any type; you’ll get an error if you try passing something which cannot be called on a std::string or which doesn’t return something convertible to a T. There’s no reason to constrain the type beyond that unless you specifically have a reason it needs to be that specific type, and in this case you don’t.
Thus, you can declare your function as
template <class T, class F>
auto split(const std::string &s, const F&& convert, char sep = ',') -> std::vector<T>

#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype( __VA_ARGS__ ) \
{ return __VA_ARGS__; }
#define OVERLOADS_OF(...) \
[](auto&&...args) \
RETURNS( __VA_ARGS__( decltype(args)(args)... )
This macro lets you take the name of a function and generate a lambda that contains the overloads of it.
auto q = split<std::size_t>( subs, OVERLOADS_OF(std::stroul) );
which is nice and concise.
Default arguments are only accessible by invoking () on the actual name of the function, and the only way to "move the name" into a different context is to stuff it into a lambda as text.
As an aside, there is a c++2a proposal by #barry to replace RETURNS(X) above with => X for lambdas. I am unaware of a currently maintained proposal to replace the OVERLOADS_OF macro (there was one a while back).
Possibly the c++2a reflection proposal would permit you to gain access to the default arguments and overload set of a function name, and fancy metaprogramming would then let you generate OVERLOADS_OF without a macro.

Related

How to pass std::isspace to function taking unary predicate as argument?

I have the following trim function
std::string trim(const std::string& str, std::function<bool(int ch)> isCharToTrim)
{
auto trimmedStart = std::find_if_not(str.begin(), str.end(), isCharToTrim);
if (trimmedStart == str.end())
{
return "";
}
else
{
auto trimmedEnd = std::find_if_not(str.rbegin(), str.rend(), isCharToTrim);
return std::string(trimmedStart, trimmedEnd.base());
}
}
When I pass std::isspace as second argument, it compiles with MSVC.
But I get an error with gcc: error: cannot resolve overloaded function 'isspace' based on conversion to type 'std::function<bool(int)>'.
Usage of the function that works on MSVC
const auto trimmed = trim(test, std::isspace);
const auto trimmed2 = trim(test, std::not_fn(std::isgraph));
const auto trimmed3 = trim(test, [](int ch) { return ch == ' '; });
What changes can I make to get it to compile on gcc? Change the argument type?
https://godbolt.org/z/81cjvrh7E
You should not use function pointers to functions in the standard library unless they are explicitly addressable functions.
You can wrap them in a lambda:
const auto trimmed = trim(test, [](auto c) { return std::isspace(static_cast<unsigned char>(c)); });
Note that it is not necessary to convert all callables to std::function just to call them or pass them to an algorithm. You can accept any callable by making the function a template:
template <typename C>
std::string trim(const std::string& str, C isCharToTrim);
The error complains about an overload because there is https://en.cppreference.com/w/cpp/locale/isspace in addition to the function you want to pass. Anyhow, strictly speaking the standard merely specifies what happens when you call std::isspace(int). There needs not actually be a function int std::isspace(int), it could be int std::isspace(int,int=42). There can be other overloads present. For this (and perhaps other) reasons it is generally not allowed to take pointers to standard functions.

returning a std::string from a variant which can hold std::string or double

I have the following code:
#include <variant>
#include <string>
#include <iostream>
using Variant = std::variant<double, std::string>;
// helper type for the visitor
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
// explicit deduction guide (not needed as of C++20)
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
std::string string_from(const Variant& v)
{
return std::visit(overloaded {
[](const double arg) { return std::to_string(arg); },
[](const std::string& arg) { return arg; },
}, v);
}
int main()
{
Variant v1 {"Hello"};
Variant v2 {1.23};
std::cout << string_from(v1) << '\n';
std::cout << string_from(v2) << '\n';
return 0;
}
I have a function called string_from() which takes a variant and converts its inner value to a string.
The variant can hold either a std::string or a double.
In case of a std::string, I just return it.
In case of a double, I create a std::string from the double and then return it.
The problem is, I don't like the fact that I'm returning a copy of the std::string in case of a string-variant. Ideally, I would return a std::string_view or another kind of string observer.
However, I cannot return a std::string_view because in case of a double-variant I need to create a new temporary std::string and std::string_view is non-owning.
I cannot return a std::string& for the same reason.
I'm wondering if there's a way to optimize the code so that I can avoid the copy in case of a string-variant.
Note in my actual use case, I obtain strings from string-variants very frequently, but very rarely from double-variants.
But I still want to be able to obtain a std::string from a double-variant.
Also, in my actual use case, I usually just observe the string, so I don't really need the copy every time. std::string_view or some other string-observer would be perfect in this case, but it is impossible due to the reasons above.
I've considered several possible solutions, but I don't like any of them:
return a char* instead of a std::string and allocate the c-string somewhere on the heap in case of a double. In this case, I would also need to wrap the whole thing in a class which owns the heap-allocated strings to avoid memory leaks.
return a std::unique_ptr<std::string> with a custom deleter which would cleanup the heap-allocated strings, but would do nothing in case the string resides in the variant. Not sure how this custom deleter would be implemented.
Change the variant so it holds a std::shared_ptr<std::string> instead. Then when I need a string from the string-variant I just return a copy of the shared_ptr and when I need a string from the double-variant I call std::make_shared().
The third solution has an inherent problem: the std::string no longer resides in the variant, which means chasing pointers and losing performance.
Can you propose any other solutions to this problem? Something which performs better than copying a std::string every time I call the function.
You can return a proxy object. (this is like your unique_ptr method)
struct view_as_string{
view_as_string(const std::variant<double, std::string>& v){
auto s = std::get_if<std::string>(&v);
if(s) ref = s;
else temp = std::to_string(std::get<double>(v));
}
const std::string& data(){return ref?*ref:temp;}
const std::string* ref = nullptr;
std::string temp;
};
Use
int main()
{
std::variant<double, std::string> v1 {"Hello"};
std::variant<double, std::string> v2 {1.23};
std::cout << view_as_string(v1).data() << '\n';
view_as_string v2s(v2);
std::cout << v2s.data() << '\n';
}
The problem is, a variant holds different types, but you're trying to find a way to represent all of them in a single type. A string representation is useful for generic logging, but it has the downsides you describe.
For variants, I don't like trying to consolidate the values back into a single common thing, because if that was easily possible then there would be no need for the variant in the first place.
Better, I think, is to defer the conversion as late as possible, and keep forwarding it on to other functions that make use of the value as it is, or convert and forward until it's used--rather than trying to extract a single value and trying to use that.
A fairly generic function might look like this:
template <typename Variant, typename Handler>
auto with_string_view(Variant const & variant, Handler && handler) {
return std::visit(overloaded{
[&](auto const & obj) {
using std::to_string;
return handler(to_string(obj));
},
[&](std::string const & str) {return handler(str); },
[&](std::string_view str) { return handler(str); },
[&](char const * str) { return handler(str); }
}, variant);
}
Since the temporary created in the generic version outlives the call to the handler, this is safe and efficient. It also shows the "forward it on" technique that I've found to be very useful with variants (and visiting in general, even for non-variants.)
Also, I don't explicitly convert to string_view, but the function could add requirements that the handler accepts string views (if that helps document the usage.)
With the above helper function you might use it like this:
using V = std::variant<std::string, double>;
V v1{4.567};
V v2{"foo"};
auto print = [](std::string_view sv) { std::cout << sv << "\n";};
with_string_view(v1, print);
with_string_view(v2, print);
Here's a full live example, expanded out a little too: https://godbolt.org/z/n7KhEW7vY
If thread safety is not an issue, you could simply use a static std::string as the backing storage when returning a double value. Then you would be able to return a std::string_view, eg:
std::string_view string_from(const Variant& v)
{
static std::string buffer;
return std::visit(overloaded {
[&buffer](const double arg) -> std::string_view { buffer = std::to_string(arg); return buffer; },
[](const std::string& arg) -> std::string_view { return arg; },
}, v);
}
Online Demo
I've come up with my own solution inspired by apple apple's solution with the view_as_string class.
Here it is:
class owning_string_view : public std::string_view
{
public:
explicit owning_string_view(const char* str) : std::string_view{str}, m_string_buffer{} {}
explicit owning_string_view(const std::string& str) : std::string_view{str}, m_string_buffer{} {}
explicit owning_string_view(std::string&& str) : std::string_view{}, m_string_buffer{std::move(str)}
{
static_cast<std::string_view&>(*this) = m_string_buffer;
}
private:
std::string m_string_buffer;
};
Instead of taking a Variant I made it more generic and it takes strings instead.
For lvalue strings it just creates a std::string_view of the string.
For rvalue strings it moves the string into the buffer.
It extends from std::string_view so it can be used in std::string_view contexts seamlessly.
Of course you have to be careful not no slice off the std::string_view part from the object when creating an rvalue owning_string_view but this is true for std::string_view as well. You have to be careful not to take a std::string_view from an rvalue std::string.
Passing a owning_string_view as a std::string_view parameter to a function is safe for the same reason it is safe to pass an rvalue std::string as a std::string_view parameter to a function. The rvalue lives during the function call.
I also realized a deeper problem when returning a string_view from my Variantclass.
If I try to extract a std::string_view or a owning_string_view from an rvalue Variant I'm still going do end up with a dangling string_view, so I added 2 functions for taking a string from the Variant:
one accepts lvalue variants only and it returns owning_string_view.
the other accepts rvalue variants only and it returns a std::string, which is moved from the variant (since the variant is an rvalue).
One more observation: Ideally, I would make the first 2 constructors of owning_string_view constexpr but I can't because the default constructor of std::string is not constexpr. I hope this is changed in the future.

Excpetion Message: Insert String Representation of Faulty Value

I want to throw an exception of type domain_error if key of type T is not a valid key.
But I don't know how I could convert any type T to a string, as long as T::operator std::string() is defined, as for instance int does not support this.
This is obvioulsy wrong, as it only works for very specific types:
throw std::domain_error("key error: "+static_cast<std::string>(key));
How can this be done?
edit
My solution after the suggestion to use template specilisation
template <class T> std::string to_string(const T t)
{
return static_cast<std::string>(t);
}
template <> std::string to_string<unsigned int>(const unsigned int i)
{
std::stringstream ss;
std::string ret;
ss << i;
ss >> ret;
return ret;
}
...
std::string domain_error(const IS& is) const
{
using namespace IDTranslator_detail;
return "key error: "+to_string(is), "error";
}
...
throw std::domain_error(domain_error(key));
It can't be done, as described, in 100% of all situations.
You must specify that a part of the contract for your template is that whatever class is passed as a parameter it must support operator std::string.
You could also write, as part of your contract, that numeric types would also be allowed, and you will implement this in your template, as a specialization that uses std::to_string.
For a robust implementation, in this situation I would use SFINAE to try std::to_string, operator std::string, and if both fail, use some bland label, like "unknown type" in the exception message. Maybe use typeid together with my compiler's demangler to, at least, get a C++ type name out of it.

Getting type names at compile time in C++ [duplicate]

This question already has answers here:
Can I obtain C++ type names in a constexpr way?
(3 answers)
Closed 1 year ago.
I want to get the type name and print it for debug purposes. I use the following code:
#include <cxxabi.h>
inline const char* demangle(const char *s) {
abi::__cxa_demangle(s, 0, 0, NULL);
}
template<typename T>
inline const char* type_name() {
return demangle(typeid(T).name());
}
It works well, but it I suppose there is an unnecessary runtime overhead. Is there any way to get a human-readable form of type ids that is computed at compile time? I am thinking of something that looks like this:
boost::mpl::type_name<MyType>::value
Which would return a string constant of the type name.
I can't see typeid(T).name() incurring a runtime overhead. typeid(expr) yes, if expr is of a polymorphic type.
It looks like the demangling probably happens at runtime, but there's not an awful lot you can do about that. If this is only for debugging then I really wouldn't worry about it too much unless your profiler indicates that this is causing your program to slow down so much that debugging other elements of it is troublesome.
I have the same need, I've solved it using the _____FUNCTION_____ maccro in a static method of my class. But you must do some runtine computation on _____FUNCTION_____ to extract the class name. You have to do some template tricks to avoid paste the same code in every class. If someone is interessed I may clean and translate my code from french  to post it.
The main advantage of this method is that you don't need to enable RRTI. On the other hand, the extraction of the class name may be compiler dependant.
template <class MyT>
class NamedClass
{
static std::string ComputeClassName()
{
std::string funcMacro=__FUNCTION__;
//compiler dependant
static const std::string start="scul::NamedClass<class ";
static const std::string end=">::ComputeClassName";
return funcMacro.substr(start.size(),funcMacro.size()-end.size()-start.size());;
}
static const std::string _ClassName;
};
template <class MyT>
const std::string NamedClass<MyT>::_ClassName=NamedClass<MyT>::ComputeClassName();
In C++ 20
You can use the standard std::source_location where its static method ::current is consteval in which you can use it at compile-time and then you can obtain the function_name method.
template <typename T>
consteval auto func_name() {
const auto& loc = std::source_location::current();
return loc.function_name();
}
template <typename T>
consteval std::string_view type_of_impl_() {
constexpr std::string_view functionName = func_name<T>();
// since func_name_ is 'consteval auto func_name() [with T = ...]'
// we can simply get the subrange
// because the position after the equal will never change since
// the same function name is used
// another notice: these magic numbers will not work on MSVC
return {functionName.begin() + 37, functionName.end() - 1};
}
template <typename T>
constexpr auto type_of(T&& arg) {
return type_of_impl_<decltype(arg)>();
}
template <typename T>
constexpr auto type_of() {
return type_of_impl_<T>();
}
Note: The function name from the source location object may vary from compiler-to-compiler and you can use the macro __PRETTY_FUNCTION__ or any other related macros if your compiler doesn't yet support the source location library.
Usage:
int x = 4;
// type_of also preserves value category and const-qualifiers
// note: it returns std::string_view
type_of(3); // int&&
type_of(x); // int&
type_of(std::as_const(x)); // const int&
type_of(std::move(x)); // int&&
type_of(const_cast<const int&&>(x)); // const int&&
struct del { del() = delete; };
type_of<del>(); // main()::del (if inside main function)
// type_of(del{}); -- error
type_of<int>(); // int
type_of<const int&>(); // const int&
type_of<std::string_view>(); // std::basic_string_view<char>
type_of([]{}); // main()::<lambda()>&&
type_of<decltype([]{})>(); // main()::<lambda()>
type_of<std::make_index_sequence<3>>(); // std::integer_sequence<long unsigned int, 0, 1, 2>
// let's assume this class template is defined outside main function:
template <auto X> struct hello {};
type_of<hello<1>>(); // hello<1>
type_of<hello<3.14f>>(); // hello<3.1400001e+0f>
// also this:
struct point { int x, y; };
type_of<hello<point{.x = 1, .y = 2}>>() // hello<point{1, 2}>
Advantage of using this type_of over demangling in typeid(...).name():
(also noted: I didn't test other compiler's ability, so I only guarantee for GCC)
You can check the value at compile-time, such that static_assert(type_of(4.0) == "double&&") is valid.
There is no runtime overhead.
The operation can be done either at runtime or compile-time (depending on the argument given whether it's usable in a constant expression).
It preserves cv-ref traits (const, volatile, & and &&).
You can alternatively use the template argument just in case the type's constructor is deleted and test without the cv-ref traits.
You could use std::type_index to cache the demangled strings.
You could use an std::map or similar data structure (splay trees for example) to cache and access the demangled name relatively quickly. It's not done in compile time though, I doubt the latter is possible.

Function template

I have a function template as this.
template<class T> T getFromString(const string& inStream)
{
istringstream stream (inStream);
T t;
stream >> t;
return t;
}
I am not getting how to use this function template. I have tried the usual method of using function template it was giving an error. Please let me know for getting out of this.
You can use it like this:
std::string a = "11";
int n = getFromString<int>(a);
This will extract the integer value from the string.
BTW, it is good to use T t = T(); inside the template as it will gurantee the initialization for the basic datatypes even if the extaction fails.
Unleashing the power of Boost:
int n = boost::lexical_cast<int>("11");
The problem is that the compiler cannot use the return type to infer the types of the function. You need to explicitly provide the type that you want as part of the function call, as #Naveen already mentioned: getFromString<int>("123"). Another approach is changing the function signature so that instead of returning it receives the type as an argument:
template <typename T>
void getFromString( const std::string & str, T & value ) { ... }
int main() {
int x;
getFromString("123",x);
}
As you provide a variable of type T in the call, the compiler is now able to infer the type from the arguments. (x is an int, so you are calling getFromString<int>). The disadvantage is that you need to create the variable in advance and user code will be more convoluted for simple use cases as int n = getFromString<int>( "123" );