Is it possible to union variable conversion function? - c++

For example, there are three variable conversion functions.
//Int
int toInt(std::string input)
{
int ret = strtol(input.c_str(), 0, 10);
return ret;
}
//Double
double toDouble(std::string input)
{
double ret = strtod(input.c_str(), 0);
return ret;
}
//Const char*
const char* toChar(std::string input)
{
return input.c_str();
}
I want to combine these functions like below:
~~ toConvert(std::string input)
{
if ( Variable type is Int )
return strtol(~~~)
else if ( Varibale type is Double )
return strtod(~~~)
...
// Using
int i = toConvert<int>(input);
double d = toConvert<double>(input);
const char* c = toConvert<const char*>(input);
Is it possible?
Please help for implemet above function.

Your "using" code is passing a template argument to toConvert(), so make sure toConvert() is actually a template, and then you can specialize it for each type you want, eg:
template<typename T>
T toConvert(std::string &input) { return T{}; /* or, throw an exception... */ }
template<>
int toConvert<int>(std::string &input)
{
return strtol(input.c_str(), 0, 10);
}
template<>
double toConvert<double>(std::string &input)
{
return strtod(input.c_str(), 0);
}
template<>
const char* toConvert<const char*>(std::string &input)
{
return input.c_str();
}
Or, if you are using C++17 or later, you can instead use if constexpr in a single template:
#include <type_traits>
template<typename T>
T toConvert(std::string &input)
{
if constexpr (std::is_same_v<T, int>)
return strtol(input.c_str(), 0, 10);
else if constexpr (std::is_same_v<T, double>)
return strtod(input.c_str(), 0);
else if constexpr (std::is_same_v<T, const char*>)
return input.c_str();
else
return T{}; // or, throw an exception, or static_assert a compiler error...
}
Notice in either case that I changed the input parameter to std::string&. Your original code was taking in the std::string by value, which means it takes in a copy of the caller's string, and so the const char* conversion would return a dangling pointer to invalid memory when the copied std::string is freed upon return. By taking a reference instead, you avoid that copy.
You might be tempted to take in a const std::string& reference instead, but that would allow calls like toConvert<const char*>("string") to compile but still return a dangling pointer, since the compiler would have to create a temporary std::string to bind to the const reference. But a string literal can't bind to a non-const reference.

That's possible using C++17's if constexpr syntax. For example:
template <typename T>
constexpr bool dependent_false = false;
template <typename T>
T convertTo(const std::string& input)
{
if constexpr (std::is_same_v<T, int>) {
return std::stoi(input);
} else if constexpr (std::is_same_v<T, double>) {
return std::stod(input);
} else {
static_assert(dependent_false<T>, "Can't convert to the specified type");
}
}
Live Demo
The whole dependent_false thing exists to make the static_assertion dependent on the template parameter so that it only gets checked when the function template is instantiated. Just an odd quirk of the C++ template rules.
Note that I left the const char* case out. It has very different semantics from the others, since the pointer returned by c_str points to memory owned by the std::string object.

Related

How can I write a version of a function to take pointer types?

std::to_string doesn't take the all the types I want, and so I have my own functions. But I'm having trouble creating a string from pointer types. In the following code I want the two calls in main() to call the (const void*) versions of toString():
std::string toString(const void* arg)
{
return std::to_string((unsigned long long) arg);
}
template <typename T>
std::string toString(T arg)
{
if constexpr (std::is_floating_point_v<T>); // Do something
// Else do something else
return std::string();
}
struct Bar {};
int main()
{
// I want pointer types to call the pointer version of the function (const void*)
Bar* bar = 0;
Bar** bar2 = 0;
toString(bar);
toString(bar2);
}
The basic idea is that I want pointer values (no matter what they're pointing to) converted to string.
You already use if constexpr, so you might do
template <typename T>
std::string toString(T arg)
{
if constexpr (std::is_pointer_v<T>) {
return std::to_string((unsigned long long) arg);
} else if constexpr (std::is_floating_point_v<T>) {
// Do something
return std::string();
} else {
// Else do something else
return std::string();
}
}

How to write function with the matching const modifier on argument and return types?

I want to write a function that extracts a pointer field from a struct. The requirement is that if I pass the struct as a const argument, the returned type should be const. If not, the returned type should not be const.
For instance,
struct S {
char *p;
};
// approach 1: two overload functions with duplicate body
auto extract(S &input) -> int * {
return reinterpret_cast<int *>(input.p + 12);
}
auto extract(const S &input) -> const int * {
return reinterpret_cast<const int *>(input.p + 12);
}
// approach 2: macro
#define macro_extract(input) (reinterpret_cast<int *>(input.p + 12))
Is there any trick in template or latest C++ standard that can write a strongly typed function without duplicating the body?
EDIT:
Changed the example a bit to reflect more accurately of the real problem.
Here's a solution with a single function template:
template<typename T,
typename = std::enable_if_t<
std::is_same_v<
std::remove_cv_t<
std::remove_reference_t<T>>, S>>>
auto extract(T&& input)
-> std::conditional_t<
std::is_const_v<
std::remove_reference_t<T>>, int const *, int *>
{
return input.p;
}
Here's a demo.
I think it goes without saying that you'd be better off with an overload set. If the function body is large, you can still call the non-const version from the const overload, and add the const there.
if constexpr and auto as return type solution:
#include <type_traits>
struct S {
int *p;
};
template<typename T>
auto extract(T &&input) {
static_assert(std::is_same_v<std::decay_t<decltype(input)>,S>, , "Only struct S is supported");
if constexpr(!std::is_const_v<std::remove_reference_t<decltype(input)>>) {
return input.p;
} else {
return const_cast<const int*>(input.p);
}
}
int main () {
S i;
using t = decltype(extract(i));
static_assert(std::is_same_v<t,int*>);
S const i_c{0};
using t_c = decltype(extract(i_c));
static_assert(std::is_same_v<t_c,const int*>);
return 0;
}
PLZ look at the ISO proposal:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4388.html
And the std::experimental::propagate_const spec:
https://en.cppreference.com/w/cpp/experimental/propagate_const
Or one can implement his own version of propagate_const.
have fun,
FM
SFINAE should be able to do this. The approximate format is:
template<class T,
class allow=std::enable_if_t<std::is_base_of_v<S, T>>>
auto extract(T&& input) -> decltype(input.p) {
return input.p;
}
Basically using universal forwarding references to make it work for anything: S, S&, const S&, S&&, volatile S&, etc.

specialize return type to void or const lvalue reference

I'm trying to accomplish the below..
enum class Options : uint8_t {
optA,
optB,
optC
};
class Test {
public:
static std::string str;
static std::vector<std::string> vec;
template<Options option>
static auto func()
{
if constexpr (option == Options::optA)
{
return str; // want this to deduce to 'const std::string', but only does so if 'const auto' (const std::string& also fine though)
}
else if constexpr (option == Options::optB)
{
return vec; // want this to deduce to 'const std::vector<std::string>&' but only does so if 'const auto&'
}
// want this to deduce to 'void' but only can if 'auto'
}
}
But of course it doesn't work for the commented reasons.
I know I could...
1) specialize the function outside of the class body for each option, and deliberately specify the return type
or 2) explicitly pass in the return type when calling the function
But is there any cleaner solution where all I need to do is pass in the single Options value into the template and the rest gets derived inside of a single function body?
const std::string& value = Test::func<Options::optA>();
const std::vector<std::string>& values = Test::func<Options::optB>();
Test::func<Options::optC>();
For a non-static func(), you can mark it as const and use decltype(auto) deduction:
template<Options option>
decltype(auto) func() const
{
if constexpr (option == Options::optA)
return (str);
else if constexpr (option == Options::optB)
return (vec);
}
str and vec are parenthesized so that decltype(auto) deduce a reference type. For optA it will return const std::string&, for optB – const std::vector<std::string>&, and void otherwise.
Demo 1
For a static member function and static members you can write:
template<Options option>
static decltype(auto) func()
{
if constexpr (option == Options::optA)
return std::as_const(str);
else if constexpr (option == Options::optB)
return std::as_const(vec);
}
Demo 2
There is no need to return a const std::string. You can just return a std::string and the caller can decide if it wants it to be const or not. If you are okay with that, then your function would become
template<Options option>
static decltype(auto) func()
{
if constexpr (option == Options::optA)
{
return str;
}
else if constexpr (option == Options::optB)
{
return const_cast<const std::vector<std::string>&>(vec);
}
else //
{ // this bit is not really needed but I like
return; // being explicit that `void` is what we want to return
//
} //
}
and now decltype(auto) will deduce for Options::optA a std::string, for Options::optB a const std::vector<std::string>& and for Options::optC , void.

C++ How can I improve this bit of template meta-program to give back the array including the size?

I've got a utility called choose_literal which chooses a literal string encoded as char*, wchar_*, char8_t*, char16_t*, char32_t* depending on the desired type (the choice).
It looks like this:
template <typename T>
constexpr auto choose_literal(const char * psz, const wchar_t * wsz, const CHAR8_T * u8z, const char16_t * u16z, const char32_t * u32z) {
if constexpr (std::is_same_v<T, char>)
return psz;
if constexpr (std::is_same_v<T, wchar_t>)
return wsz;
#ifdef char8_t
if constexpr (std::is_same_v<T, char8_t>)
return u8z;
#endif
if constexpr (std::is_same_v<T, char16_t>)
return u16z;
if constexpr (std::is_same_v<T, char32_t>)
return u32z;
}
I supply a little preprocessor macro to make this work w/o having to type each of those string encodings manually:
// generates the appropriate character literal using preprocessor voodoo
// usage: LITERAL(char-type, "literal text")
#define LITERAL(T,x) details::choose_literal<T>(x, L##x, u8##x, u##x, U##x)
This of course only works for literal strings which can be encoded in the target format by the compiler - but something like an empty string can be, as can ASCII characters (i.e. a-z, 0-9, etc., which have representations in all of those encodings).
e.g. here's a trivial bit of code that will return the correct empty-string given a valid character type 'T':
template <typename T>
constexpr const T * GetBlank() {
return LITERAL(T, "");
}
This is great as far as it goes, and it works well enough in my code.
What I'd like to do is to refactor this such that I get back the character-array including its size, as if I'd written something like:
const char blank[] = "";
or
const wchar_t blank[] = L"";
Which allows the compiler to know the length of the string-literal, not just its address.
My choose_literal<T>(str) returns only the const T * rather than the const T (&)[size] which would be ideal.
In general I'd love to be able to pass such entities around intact - rather than have them devolve into just a pointer.
But in this specific case, is there a technique you might point me towards that allows me to declare a struct with a data-member for the desired encoding which then also knows its array-length?
A little bit of constexpr recursion magic allows you to return a string_view of the appropriate type.
#include <string_view>
#include <type_traits>
#include <iostream>
template <typename T, class Choice, std::size_t N, class...Rest>
constexpr auto choose_literal(Choice(& choice)[N], Rest&...rest)
{
using const_char_type = Choice;
using char_type = std::remove_const_t<const_char_type>;
if constexpr (std::is_same_v<T, char_type>)
{
constexpr auto extent = N;
return std::basic_string_view<char_type>(choice, extent - 1);
}
else
{
return choose_literal<T>(rest...);
}
}
int main()
{
auto clit = choose_literal<char>("hello", L"hello");
std::cout << clit;
auto wclit = choose_literal<wchar_t>("hello", L"hello");
std::wcout << wclit;
}
https://godbolt.org/z/4roZ_O
If it were me, I'd probably want to wrap this and other functions into a constexpr class which offers common services like printing the literal in the correct form depending on the stream type, and creating the correct kind of string from the literal.
For example:
#include <string_view>
#include <type_traits>
#include <iostream>
#include <tuple>
template <typename T, class Choice, std::size_t N, class...Rest>
constexpr auto choose_literal(Choice(& choice)[N], Rest&...rest)
{
using const_char_type = Choice;
using char_type = std::remove_const_t<const_char_type>;
if constexpr (std::is_same_v<T, char_type>)
{
constexpr auto extent = N;
return std::basic_string_view<char_type>(choice, extent - 1);
}
else
{
return choose_literal<T>(rest...);
}
}
template<class...Choices>
struct literal_chooser
{
constexpr literal_chooser(Choices&...choices)
: choices_(choices...)
{}
template<class T>
constexpr auto choose()
{
auto invoker = [](auto&...choices)
{
return choose_literal<T>(choices...);
};
return std::apply(invoker, choices_);
}
std::tuple<Choices&...> choices_;
};
template<class Char, class...Choices>
std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& os, literal_chooser<Choices...> chooser)
{
return os << chooser.template choose<Char>();
}
template<class Char, class...Choices>
std::basic_string<Char> to_string(literal_chooser<Choices...> chooser)
{
auto sview = chooser.template choose<Char>();
return std::basic_string<Char>(sview.data(), sview.size());
}
int main()
{
auto lit = literal_chooser("hello", L"hello");
std::cout << lit << std::endl;
std::wcout << lit << std::endl;
auto s1 = to_string<char>(lit);
auto s2 = to_string<wchar_t>(lit);
std::cout << s1 << std::endl;
std::wcout << s2 << std::endl;
}
The use of the reference argument type Choices& is important. C++ string literals are references to arrays of const Char. Passing by value would result in the literal being decayed into a pointer, which would lose information about the extent of the array.
we can add other services, written in terms of the literal_chooser:
template<class Char, class...Choices>
constexpr std::size_t size(literal_chooser<Choices...> chooser)
{
auto sview = chooser.template choose<Char>();
return sview.size();
}
We're going to change the function so that it takes a const T (&)[size] for each input, and the return type is going to be decltype(auto). Using decltype(auto) prevents the return from decaying into a value, preserving things like references to arrays.
Updated function:
template <typename T, size_t N1, size_t N2, size_t N3, size_t N4>
constexpr decltype(auto) choose_literal(const char (&psz)[N1], const wchar_t (&wsz)[N2], const char16_t (&u16z)[N3], const char32_t (&u32z)[N4]) {
if constexpr (std::is_same<T, char>())
return psz;
if constexpr (std::is_same<T, wchar_t>())
return wsz;
if constexpr (std::is_same<T, char16_t>())
return u16z;
if constexpr (std::is_same<T, char32_t>())
return u32z;
}
In main, we can assign the result to something of type auto&&:
#define LITERAL(T,x) choose_literal<T>(x, L##x, u##x, U##x)
int main() {
constexpr auto&& literal = LITERAL(char, "hello");
return sizeof(literal); // Returns 6
}
Potential simplification
We can simplify the choose_literal function by making it recursive, that way it can be expanded for any number of types. This works without any changes to the LITERAL macro.
template<class T, class Char, size_t N, class... Rest>
constexpr decltype(auto) choose_literal(const Char(&result)[N], Rest const&... rest) {
if constexpr(std::is_same_v<T, Char>)
return result;
else
return choose_literal<T>(rest...);
}

Conversion and overload deduction based on return type

I've seen in the C++ core guidelines that it is preferable to return output values from functions.
I am trying to understand if this is convenient for generic code.
For instance, in order to convert from a string to a certain value I'd normally do something like:
template<class T>
T convertTo(const std::string& value)
{
// Do conversion
return convertedValue;
}
// Usage
convertTo<float>("test");
Without specifying the type I'd do:
template<class T>
void convertTo(const std::string& value, T& outputValue)
{
// Do conversion
// outputValue = convertedType
}
// Usage
float myVar{};
convertTo("test", myVar);
I know also that you can do something like:
auto convertTo(const std::string& value, anotherInputPerhaps) ->decltype(myexpression)
{
// get the type to return basing on anotherInputPerhaps
return /*convertedValue*/
}
The problem here is how to get the right converted value, possibly without passing any input or maybe using a defaulted value. Is this possible?
Thanks
[EDIT] Looking for something that does not introduce overhead
You might return class with conversion operator, something like:
struct Converter
{
template <typename T>
operator T() const /*&&*/ { /*Do conversion*/ return {}; }
const std::string& s;
};
Converter convert(const std::string& value)
{
return { value };
}
With usage:
float f = convert("test");
int i = convert("test");
std::vector<int> v = convert("test");
Demo
With default value you can also do:
template<class T>
T convertTo(const std::string& value, T default_value)
{
// DO Conversion
if( conversion success)
return convertedValue;
else
return default_value;
}
And call it like this:
float myVar= DEFAULT_VALUE;
myVar = convertTo("test", myVar);