Loading...
Searching...
No Matches
stringconvert.h
Go to the documentation of this file.
1#ifndef _BBM_STRING_CONVERT_H_
2#define _BBM_STRING_CONVERT_H_
3
4#include <array>
5#include <string>
6#include <sstream>
7#include <vector>
8#include <map>
9#include <set>
10
11#include "concepts/named.h"
12#include "concepts/reflection.h"
14
15#include "util/string_util.h"
16#include "util/typestring.h"
17#include "util/reflection.h"
18#include "util/constfor.h"
19#include "util/tuple.h"
20#include "util/vector_util.h"
21
22#include "core/error.h"
23#include "core/args.h"
24
25
26/************************************************************************/
27/*! \file stringconvert.h
28
29 \brief Convert a string to an object and vice versa
30*************************************************************************/
31
32namespace bbm {
33
34 namespace detail {
35 //! \brief Helper concept: check if T has a typedef contructor_args_t and
36 //! it points to a bbm::args
37 template<typename T> concept has_constructor_args_t = bbm::concepts::trait_wrapper<typename std::decay_t<T>::constructor_args_t, bbm::is_args>;
38 }
39
40 /**********************************************************************/
41 /*! \brief Default converter class; should be specialized. Has a fall
42 through for types with reflection; if not it will throw a compile error
43 when trying to call the static to/fromString methods.
44 **********************************************************************/
45 template<typename T>
47 {
48 /******************************************************************/
49 /*! \brief convert a string to a type T
50
51 If T has a constructor_args_t, then use this to convert from a string.
52 Otherwise, if T supports reflection AND a trivial constructor, then use
53 reflection to set the attributes. In both cases, if T meets
54 concepts::named then the name must match the keyword. If T supports
55 enumerate reflection, then use this.
56
57 Note: these cases are defined in the base case for string_converter
58 such that they can be overwritten by type specific specializations.
59 ******************************************************************/
60 template<typename = T> requires ((concepts::reflection::attributes<T> && std::constructible_from<T>) || bbm::detail::has_constructor_args_t<T>) || concepts::reflection::enumerate<T>
61 static inline T fromString(const std::string& str)
62 {
63 // check name
64 if constexpr (concepts::named<T>)
65 {
66 auto [key, value] = bbm::string::get_keyword(str);
67
68 if( std::string(std::decay_t<T>::name) != key ) throw std::invalid_argument(std::string("BBM: mismatched object name ") + key + ", expected: " + std::string(std::decay_t<T>::name));
69
70 // if has constructor_args_t; get values and make T
71 if constexpr (bbm::detail::has_constructor_args_t<T>)
72 {
73 auto args = bbm::fromString<typename std::decay_t<T>::constructor_args_t>(value);
74 return std::make_from_tuple<T>(args.values());
75 }
76
77 // if has attributes, then copying values
78 else
79 {
80 T obj;
81
82 // copy values
84 bbm::reflection::attributes(obj) = bbm::fromString<str_type>(value);
85
86 return obj;
87 }
88 }
89
90 // if has enumeration reflection, then search the matching name
91 else if constexpr (concepts::reflection::enumerate<T>)
92 {
93 return linear_search_named(str, bbm::reflection::enum_v<T>, []<size_t IDX, typename ENUM>(const std::string& value, ENUM&& enum_v) -> T
94 {
95 if constexpr (IDX == std::decay_t<ENUM>::size)
96 throw std::invalid_argument(std::string("BBM: name '") + value + "' not found in enumeration: " + std::string(typestring<std::decay_t<T>>));
97 else return std::get<IDX>(enum_v);
98 });
99 }
100
101 // Done.
102 }
103
104
105 /*******************************************************************/
106 /*! \brief convert an object to a type T
107
108 If T support reflection, then convert the attributes to a string. If T
109 also meets concepts::named, then prefix the name.
110 ********************************************************************/
112 static inline std::string toString(const T& obj)
113 {
114 std::string result;
115
116 // add name
117 if constexpr (concepts::named<T>) result = std::string(std::decay_t<T>::name);
118
119 // add attributes if attribute reflection
122
123 // add names if enumerate
125 {
126 CONSTFOR(IDX, bbm::reflection::enum_v<T>.size,
127 {
128 if(obj == std::get<IDX>(bbm::reflection::enum_v<T>))
129 result += std::string( bbm::reflection::enum_v<T>.template name<IDX> );
130 });
131 }
132
133 // done.
134 return result;
135 }
136 };
137
138
139 /**********************************************************************/
140 /*! @{ \name Scalar convertors
141 **********************************************************************/
142 template<> struct string_converter<float>
143 {
144 static inline float fromString(const std::string& str) { return std::stof(str); }
145 static inline std::string toString(float v) { std::stringstream ss; ss << v; return ss.str(); } // prefer this over to_string (i.e., 1 vs 1.0)
146 };
147
148 template<> struct string_converter<double>
149 {
150 static inline double fromString(const std::string& str) { return std::stod(str); }
151 static inline std::string toString(double v) { std::stringstream ss; ss << v; return ss.str(); } // prefer this over to_string
152 };
153
154 template<> struct string_converter<long double>
155 {
156 static inline long double fromString(const std::string& str) { return std::stold(str); }
157 static inline std::string toString(long double v) { std::stringstream ss; ss << v; return ss.str(); } // prefer this over to_string
158 };
159
160 template<> struct string_converter<int>
161 {
162 static inline int fromString(const std::string& str) { return std::stoi(str); }
163 static inline std::string toString(int v) { return std::to_string(v); }
164 };
165
166 template<> struct string_converter<long>
167 {
168 static inline long fromString(const std::string& str) { return std::stol(str); }
169 static inline std::string toString(long v) { return std::to_string(v); }
170 };
171
172 template<> struct string_converter<long long>
173 {
174 static inline long long fromString(const std::string& str) { return std::stoll(str); }
175 static inline std::string toString(long long v) { return std::to_string(v); }
176 };
177
178 template<> struct string_converter<unsigned int>
179 {
180 static inline unsigned int fromString(const std::string& str) { return std::stoul(str); }
181 static inline std::string toString(unsigned int v) { return std::to_string(v); }
182 };
183
184 template<> struct string_converter<unsigned long>
185 {
186 static inline unsigned long fromString(const std::string& str) { return std::stoul(str); }
187 static inline std::string toString(unsigned long v) { return std::to_string(v); }
188 };
189
190 template<> struct string_converter<unsigned long long>
191 {
192 static inline unsigned long long fromString(const std::string& str) { return std::stoull(str); }
193 static inline std::string toString(unsigned long long v) { return std::to_string(v); }
194 };
195 //! @}
196
197 /**********************************************************************/
198 /*! \brief bool conversion
199 **********************************************************************/
200 template<>
201 struct string_converter<bool>
202 {
203 static inline bool fromString(const std::string& str)
204 {
205 // cast to lower case to match different capitalizations of 'true' and 'false'
206 std::string newStr(str);
207 std::transform(str.begin(), str.end(), newStr.begin(), [](unsigned char c) { return std::tolower(c); });
208
209 // determine of true/1 of false/0
210 bool True = (newStr == "true") || (newStr == "1");
211 bool False = (newStr == "false") || (newStr == "0");
212
213 // If neither true nor false, then throw error
214 if(!True && !False) throw std::invalid_argument(std::string("BBM: cannot convert to bool from: ") + str);
215
216 // Done.
217 return True;
218 }
219
220 static inline std::string toString(bool b)
221 {
222 if(b) return std::string("True");
223 else return std::string("False");
224 }
225 };
226
227 /**********************************************************************/
228 /*! \brief string conversion
229 **********************************************************************/
230 template<>
231 struct string_converter<std::string>
232 {
233 static inline std::string fromString(const std::string& str)
234 {
235 // remove quotes
236 const char* quotes = "\"' \r\n\t\v";
237 size_t s = str.find_first_not_of(quotes);
238 size_t e = str.find_last_not_of(quotes);
239
240 // throw error if no quotes found
241 if(s > e) throw std::invalid_argument(std::string("BBM: connect convert to string; unbalanced quotes in: ") + str);
242
243 // remove qoutes
244 return str.substr(s, e-s+1);
245 }
246
247 static inline std::string toString(const std::string& str)
248 {
249 return std::string("\"") + str + std::string("\"");
250 }
251 };
252
253 /**********************************************************************/
254 /*! \brief string_literal conversion (read only)
255 **********************************************************************/
256 template<size_t N>
258 {
259 static inline std::string toString(const string_literal<N>& str)
260 {
261 return std::string(str);
262 }
263 };
264
265 /**********************************************************************/
266 /*! \brief char conversion
267 **********************************************************************/
269 struct string_converter<T>
270 {
271 static inline T fromString(const std::string& str)
272 {
273 // char must be surrounded by ' '.
274 if(str.size() != 3 || str[0] != '\'' || str[2] != '\'') throw std::invalid_argument(std::string("BBM: cannot convert to " + std::string(typestring<T>) + " from: " + str));
275
276 // Done.
277 else return str[1];
278 }
279
280 static inline std::string toString(const T& c)
281 {
282 return std::string("'") + c + std::string("'");
283 }
284 };
285
286
287 /**********************************************************************/
288 /*! \brief convert a bbm vector
289 **********************************************************************/
290 template<typename T>
292 {
293 static inline bbm::vector<T> fromString(const std::string& str)
294 {
295 std::vector<T> result;
296
297 // split in arguments
299
300 // try to convert each argument to T
301 try {
302 for(auto& a : args) result.push_back( bbm::fromString<T>(a) );
303 } catch(...) {
304 throw std::invalid_argument(std::string("BBM: cannot convert to vector<") + std::string(typestring<T>) + "> from: " + str);
305 }
306
307 // Done.
308 return result;
309 }
310
311 static inline std::string toString(const bbm::vector<T>& vec)
312 {
313 std::string result("(");
314 for(auto itr=vec.begin(); itr != vec.end(); ++itr)
315 {
316 if(itr != vec.begin()) result += ", ";
317 result += bbm::toString(*itr);
318 }
319 result += ")";
320 return result;
321 }
322 };
323
324 /**********************************************************************/
325 /*! \brief convert a std::vector (forward to bbm::vector)
326 **********************************************************************/
327 template<typename T> struct string_converter<std::vector<T>> : public string_converter<bbm::vector<T>> {};
328
329 /**********************************************************************/
330 /*! \brief convert to a fixed length array
331 **********************************************************************/
332 template<typename T, size_t N>
333 struct string_converter<std::array<T, N>>
334 {
335 static inline std::array<T,N> fromString(const std::string& str)
336 {
337 std::array<T, N> arr;
338
339 // try to get vector
340 bbm::vector<T> vec;
341 try {
342 vec = bbm::fromString<bbm::vector<T>>(str);
343 } catch(...) {
344
345 // alternative: try to get single value
346 try {
347 vec.push_back( bbm::fromString<T>(str) );
348 } catch(...) {
349
350 // failure in both cases
351 throw std::invalid_argument(std::string("BBM: cannot convert to std::array<") + std::string(typestring<T>) + ", " + std::to_string(N) + "> from: " + str);
352 }}
353
354 // copy from vector
355 if(vec.size() == N) std::copy(vec.begin(), vec.end(), arr.begin());
356 else if(vec.size() == 1) std::fill(arr.begin(), arr.end(), vec[0]);
357 else throw std::invalid_argument(std::string("BBM: too few arguments to convert to std::array<") + std::string(typestring<T>) + ", " + std::to_string(N) + ">. Found " + std::to_string(vec.size()) + " argument in: " + str);
358
359 // Done.
360 return arr;
361 }
362
363 static inline std::string toString(const std::array<T,N>& arr)
364 {
365 std::string result("[");
366 for(auto itr=arr.begin(); itr != arr.end(); ++itr)
367 {
368 if(itr != arr.begin()) result += ", ";
369 result += bbm::toString(*itr);
370 }
371 result += "]";
372 return result;
373 }
374 };
375
376 /**********************************************************************/
377 /*! \brief convert tuple
378 **********************************************************************/
379 template<typename... Ts>
380 struct string_converter<std::tuple<Ts...>>
381 {
382 static inline std::tuple<Ts...> fromString(const std::string& str)
383 {
385
386 // check length
387 if(args.size() != sizeof...(Ts)) throw std::invalid_argument("BBM: too few arguments to convert to " + std::string(typestring<std::tuple<Ts...>>) + ", expected " + std::to_string(sizeof...(Ts)) + " but found " + std::to_string(args.size()) + " in: " + str);
388
389 // create tuple
390 auto args_to_tup = [&]<size_t... IDX>(std::index_sequence<IDX...>)
391 {
392 return std::make_tuple( bbm::fromString<std::tuple_element_t<IDX, std::tuple<Ts...>>>(args[IDX])... );
393 };
394
395 // try conversion
396 try {
397 return args_to_tup(std::make_index_sequence<sizeof...(Ts)>{});
398 } catch(...) {
399 throw std::invalid_argument("BBM: cannot convert to " + std::string(typestring<std::tuple<Ts...>>) + " from: " + str);
400 }
401
402 // Done.
403 }
404
405 static inline std::string toString(const std::tuple<Ts...>& tup)
406 {
407 std::string result("(");
408 CONSTFOR(idx, sizeof...(Ts),
409 {
410 if constexpr (idx != 0) result += ", ";
411 result += bbm::toString(std::get<idx>(tup));
412 });
413 result += ")";
414 return result;
415 }
416 };
417
418 /**********************************************************************/
419 /*! \brief convert a named tuple
420 *********************************************************************/
421 template<typename TUP, string_literal... NAMES>
422 struct string_converter<named<TUP, NAMES...>>
423 {
424 using type = named<TUP, NAMES...>;
425 static constexpr size_t size = sizeof...(NAMES);
426
427 static inline type fromString(const std::string& str)
428 {
430
431 // check length
432 if(args.size() != size) throw std::invalid_argument("BBM: too few arguments to convert to " + std::string(typestring<type>) + ", expected " + std::to_string(size) + " but found " + std::to_string(args.size()) + " in: " + str);
433
434 // create name list
435 std::array<std::string, size> names;
436 CONSTFOR(idx, size, { names[idx] = type::template name<idx>; });
437
438 // create key/value list from args
439 std::array<std::pair<std::string, std::string>, size> keyval;
440 for(size_t idx=0; idx != size; ++idx)
441 keyval[idx] = bbm::string::split_eq(args[idx]);
442
443 // find keyword position
444 auto get_permutation = [&](size_t idx)
445 {
446 auto key = keyval[idx].first;
447
448 // if no keyword
449 if(key.empty()) return idx;
450
451 // else, find keyword (slow linear search; assumes only a few names)
452 auto match = std::find(std::begin(names), std::end(names), key);
453
454 // throw error if not found
455 if(match == std::end(names)) throw std::invalid_argument("BBM: cannot convert to " + std::string(typestring<type>) + ": invalid name: " + key + " in " + str);
456
457 return size_t(std::distance(std::begin(names), match));
458 };
459
460 // create index permuation
461 std::array<size_t, size> perm;
462 std::array<bool, size> used; std::fill(std::begin(used), std::end(used), false);
463
464 for(size_t idx=0; idx < size; ++idx)
465 {
466 size_t match = get_permutation(idx);
467 perm[idx] = match;
468 used[match] = true;
469 }
470
471 // check if each element is assigned
472 for(size_t idx=0; idx < size; ++idx)
473 if(!used[idx]) throw std::invalid_argument("BBM: cannot convert to " + std::string(typestring<type>) + ": " + std::to_string(idx) + " element (" + names[idx] + ") not assigned.");
474
475 // create named tuple
476 auto create_named = [&]<size_t... IDX>(std::index_sequence<IDX...>)
477 {
478 return make_named<NAMES...>( bbm::fromString<std::tuple_element_t<IDX, type>>(keyval[perm[IDX]].second)... );
479 };
480
481 // Done.
482 return create_named( std::make_index_sequence<size>{} );
483 }
484
485 static inline std::string toString(const named<TUP, NAMES...>& obj)
486 {
487 std::string result("(");
488 CONSTFOR(idx, sizeof...(NAMES),
489 {
490 if constexpr (idx != 0) result += ", ";
491
492 result += std::string(std::decay_t<decltype(obj)>::template name<idx>);
493 result += " = ";
494 result += bbm::toString(std::get<idx>(obj));
495 });
496 result += ")";
497 return result;
498 }
499 };
500
501 /**********************************************************************/
502 /*! \brief convert args<...>
503 **********************************************************************/
504 template<typename ARGS> requires is_args_v<ARGS>
505 struct string_converter<ARGS>
506 {
507 static inline std::string toString(const ARGS& args)
508 {
509 return bbm::toString(args.values());
510 }
511
512 static inline ARGS fromString(const std::string& str)
513 {
515
516 // check if size of args does not exceed the number of ARG in ARGS
517 if(args.size() > ARGS::size) throw std::invalid_argument(std::string("BBM: expected at most ") + std::to_string(ARGS::size) + " arguments, found " + std::to_string(args.size()) + " in: " + str);
518
519 // create run-time searchable list of ARG names
520 std::set<std::string> arg_names;
521 CONSTFOR(idx, ARGS::size,
522 {
523 arg_names.insert( std::string(ARGS::template name<idx>) );
524 });
525
526 // extract values and names of arguments in string
527 std::map<std::string, size_t> name_map;
528 std::vector<bool> named_arg;
529 std::vector<std::string> values;
530
531 for(size_t idx=0; idx != args.size(); ++idx)
532 {
533 auto [key, value] = bbm::string::split_eq(args[idx]);
534
535 // if named, check if valid name and add to map
536 if(key != "")
537 {
538 named_arg.push_back(true);
539 if(arg_names.contains(key)) name_map[key] = idx;
540 else throw std::invalid_argument(std::string("BBM: invalid argument name: ") + key + "(" + value + ") in: " + str);
541 }
542 else named_arg.push_back(false);
543
544 // store value
545 values.push_back(value);
546 }
547
548 // retrieve bbm::arg from string or set to default value
549 auto retrieve_arg = [&]<size_t IDX>(void)
550 {
551 using arg_t = std::decay_t<typename ARGS::template type<IDX>>;
552 using type = std::decay_t<typename arg_t::type>;
553
554 // does ARG::name exist in args?
555 auto name_itr = name_map.find(std::string(arg_t::name));
556 if(name_itr != name_map.end()) return arg_t( bbm::fromString<type>(values[name_itr->second]) );
557
558 // else check position
559 if(IDX < values.size() && !named_arg[IDX]) return arg_t( bbm::fromString<type>(values[IDX]) );
560
561 // else check if default value
562 if constexpr (std::is_constructible_v<arg_t>) return arg_t();
563
564 // else fail
565 else throw std::invalid_argument(std::string("BBM: unable to find argument ") + std::string(arg_t::name) + " in: " + str);
566 };
567
568 // for each ARG in ARGS, get value
569 auto create_args = [&]<size_t... IDX>(std::index_sequence<IDX...>)
570 {
571 return ARGS( retrieve_arg.template operator()<IDX>()... );
572 };
573
574 // Done.
575 return create_args(std::make_index_sequence<ARGS::size>{});
576 }
577 };
578
579
580 /**********************************************************************/
581 /*! \brief fromString alias
582 **********************************************************************/
583 template<typename T> requires concepts::from_stringconvert<T>
584 inline T fromString(const std::string& str)
585 {
586 if constexpr (concepts::has_fromString<T>) return std::decay_t<T>::fromString(str);
588 }
589
590 /**********************************************************************/
591 /*! \brief toString alias
592 **********************************************************************/
593 template<typename T> requires concepts::to_stringconvert<T>
594 inline std::string toString(const T& obj)
595 {
596 if constexpr (concepts::has_toString<T>) return obj.toString();
598 }
599
600
601} // end namespace bbm
602
603#endif /* _BBM_STRING_CONVERT_H_ */
Provides a more flexible argument passing to function and methods.
Definition: vector_util.h:27
Concept to check if type has a fromString member.
Definition: stringconvert.h:57
Concept to check if type has a toString member.
Definition: stringconvert.h:48
A named class is a class that contains a static constexpr string_literal name.
Definition: named.h:19
attribute reflection allows to enumerate and direct access to the attributes of a class....
Definition: reflection.h:34
concept to check if a enum supports reflection
Definition: reflection.h:65
true if type is the same as any of the listed types
Definition: util.h:31
Concept wrapper around a type trait: check if T meets the type TRAIT<T,ARGS...>
Definition: util.h:19
named (class) concept.
Complile-time for loop.
#define CONSTFOR(IDX, NUMITR,...)
HELPER MACRO.
Definition: constfor.h:63
Predefined exceptions for common errors.
concept to check if a type has a valid string_converter.
constexpr decltype(auto) attributes(T &&t)
Definition: reflection.h:200
std::pair< std::string, std::string > split_eq(const std::string &str)
split a string of the form "key = val" in key and value. If no '=', then return an empty key.
Definition: string_util.h:77
std::pair< std::string, std::string > get_keyword(const std::string &str)
Return the keyword substring appearing an open bracket, and the arguments appearing in the brackets: ...
Definition: string_util.h:65
std::string remove_brackets(const std::string &str)
remove surrounding backets
Definition: string_util.h:37
std::vector< std::string > split_args(const std::string &str)
Split a string based on comma's if not surrounded by brackets.
Definition: string_util.h:94
Definition: aggregatebsdf.h:29
constexpr named< anonymize_t< T >, NAMES... > make_named(T &&t)
Make a named of a gettable type (with size == #NAMES); renames if the type is a named container.
Definition: named.h:293
static constexpr std::string_view typestring
Definition: typestring.h:51
detail::is_args_impl< std::decay_t< T > > is_args
Definition: args.h:221
auto linear_search_named(const std::string &str, NAMED &&named, PROCESS &&process, Ts &&... context)
linear search for unsorted named tuples
Definition: named_util.h:380
T fromString(const std::string &)
fromString alias
Definition: stringconvert.h:584
size_t size(T &&t)
Definition: iterator_util.h:22
decltype(value_copy_named(std::declval< T >())) value_copy_named_t
type of value copying a named typle
Definition: named_util.h:27
std::string toString(const T &)
toString alias
Definition: stringconvert.h:594
decltype(auto) value(T &&t)
return the value of an attribute, or if not an attribute the object
Definition: attribute_value.h:20
Definition: named.h:325
Helper method for processing strings.
Forward declaration.
Definition: args.h:248
static constexpr size_t size
Definition: args.h:282
constexpr auto values(void) const
Returns a tuple of all arguments' values.
Definition: args.h:291
named container
Definition: named.h:131
static std::string toString(const ARGS &args)
Definition: stringconvert.h:507
static ARGS fromString(const std::string &str)
Definition: stringconvert.h:512
static std::string toString(const T &c)
Definition: stringconvert.h:280
static T fromString(const std::string &str)
Definition: stringconvert.h:271
static std::string toString(const bbm::vector< T > &vec)
Definition: stringconvert.h:311
static bbm::vector< T > fromString(const std::string &str)
Definition: stringconvert.h:293
static std::string toString(bool b)
Definition: stringconvert.h:220
static bool fromString(const std::string &str)
Definition: stringconvert.h:203
static double fromString(const std::string &str)
Definition: stringconvert.h:150
static std::string toString(double v)
Definition: stringconvert.h:151
static std::string toString(float v)
Definition: stringconvert.h:145
static float fromString(const std::string &str)
Definition: stringconvert.h:144
static std::string toString(int v)
Definition: stringconvert.h:163
static int fromString(const std::string &str)
Definition: stringconvert.h:162
static long fromString(const std::string &str)
Definition: stringconvert.h:168
static std::string toString(long v)
Definition: stringconvert.h:169
static std::string toString(long double v)
Definition: stringconvert.h:157
static long double fromString(const std::string &str)
Definition: stringconvert.h:156
static long long fromString(const std::string &str)
Definition: stringconvert.h:174
static std::string toString(long long v)
Definition: stringconvert.h:175
static std::string toString(const named< TUP, NAMES... > &obj)
Definition: stringconvert.h:485
static type fromString(const std::string &str)
Definition: stringconvert.h:427
static std::string toString(const std::array< T, N > &arr)
Definition: stringconvert.h:363
static std::array< T, N > fromString(const std::string &str)
Definition: stringconvert.h:335
static std::string fromString(const std::string &str)
Definition: stringconvert.h:233
static std::string toString(const std::string &str)
Definition: stringconvert.h:247
static std::string toString(const std::tuple< Ts... > &tup)
Definition: stringconvert.h:405
static std::tuple< Ts... > fromString(const std::string &str)
Definition: stringconvert.h:382
static std::string toString(const string_literal< N > &str)
Definition: stringconvert.h:259
static std::string toString(unsigned int v)
Definition: stringconvert.h:181
static unsigned int fromString(const std::string &str)
Definition: stringconvert.h:180
static std::string toString(unsigned long v)
Definition: stringconvert.h:187
static unsigned long fromString(const std::string &str)
Definition: stringconvert.h:186
static std::string toString(unsigned long long v)
Definition: stringconvert.h:193
static unsigned long long fromString(const std::string &str)
Definition: stringconvert.h:192
forward decalaration
Definition: stringconvert.h:47
static T fromString(const std::string &str)
convert a string to a type T
Definition: stringconvert.h:61
static std::string toString(const T &obj)
convert an object to a type T
Definition: stringconvert.h:112
Definition: string_literal.h:16
Extensions for the STL tuple class.
produce stringview of type name of a type. Avoids using typeid for GCC, MSVC, and CLANG....
Compile-time reflection of:
Extensions for the STL vector class.