How to avoid narrowing conversion with floating point literals inside template functions - c++

What do you usually do with floating point literals inside template functions?
Suppose that we have the following code:
template <typename T>
struct Foo
{
T bar;
};
template <typename T>
void foo(T val)
{
Foo<T> instance = { val * 5.0 };
}
int main()
{
foo(0.0f);
}
http://coliru.stacked-crooked.com/a/b159117097cc2461
It gives me the following warning / error (depending on the compiler / flags):
narrowing conversion of '(((double)val) * 5.0e+0)' from 'double' to 'float' inside { } [-Wnarrowing]
Foo<T> instance = { val * 5.0 };
How is it usually avoided? Should I just wrap any floating point literal in T(0.0) like:
Foo<T> instance = { val * T(5.0) };
Or is there any more elegant solution?

I would argue that T(5.0) is the most elegant solution. If T is a double then the conversion should be ignored by the compiler to which it is the same as writing 5.0. If T is a float then the conversion should resolved at compile time being equivalent writing as a float literal 5.0f.

If you are only dealing with a small number of well-defined magic constants but you need full control over the value of those constants for all possible Ts, it might make sense moving them to a traits class:
template<typename T>
struct FooTraits;
template<>
struct FooTraits<float> { static constexpr float magicN() { return 5.0f; } };
template<>
struct FooTraits<double> { static constexpr double magicN() { return 5.0; } };
template <typename T>
void foo(T val)
{
Foo<T> instance = { val * FooTraits<T>::magicN() };
}
This is some significant overhead in terms of boilerplate, so only do this if you actually need the added flexibility. If a simple cast to T works for all your use cases, there's nothing wrong with that.

How is it usually avoided?
I don’t think you should ‘avoid’ it as such, I’d say it depends on the final function semantics.
That is, if you want to disallow narrowing you use {} and let the compilation fail ( at least, as of >=c++11 );
if you want to allow narrowing to T on the final result you write instance = T( val * 5.0 ) and let converions do the rest for each possible T;
if you want to allow narrowing to T in intermidiate results or constants you wrap in T() there;
if you want the user to decide, you add a trait/policy class performing the final/intermidiate conversions …
that said, on one thing I'm sure: as a user of your function, I'd be very uncomfortable if any of the possibilities above were undocumented, or unreasonable given the function ultimate goal...
BTW, if you're question focuses only on constants, then I'd follow boost approach, maybe with the aid of c++14's variable templates.

Related

Cleaner way to specify type to get from a std::variant?

I've got code that can be simplified to
std::variant<float, int> v[2] = foo();
int a = std::get<decltype(a)>(v[0]);
float b = std::get<decltype(b)>(v[1]);
Obviously this can go throw if foo() returns the wrong variants, but that's not my problem here. (The real code has a catch). My problem is that the decltype(a) violates the Don't Repeat Yourself principle.
Is there a cleaner way to initialize a and b, and still throw if the types do not match expectations? In particular, I don't want a static_cast<int>(std::get<float>(v)) if the variant contains a float while I'm trying to initialize an int.
You could wrap your call to get in a template that implicitly converts to the target type.
template<typename... Ts>
struct variant_unwrapper {
std::variant<Ts...> & var;
template <typename T>
operator T() { return std::get<T>(var); }
};
See it on coliru
IMO it would be nice to allow template deduction to take over, so providing a helper function should do the job:
template<typename T, typename...VariantParams>
void get_from(const std::variant<VariantParams...>& v, T& value)
{
value = ::std::get<T>(v);
}
int a;
get_from(v[0], a);
As #paulo says in the comments, seems like the DRY solution is to use auto for the declaration, changing:
int a = std::get<decltype(a)>(v[0]);
to:
auto a = std::get<int>(v[0]);
You only name the type (int) and the variable (a) once each. Doesn't work if you separate declaration and initialization, so you'd still need:
int a;
...
a = std::get<decltype(a)>(v[0]);
in that case, but if you write all your C++ code deferring declarations until the point of definition, it's not needed often.

C++ template function that takes float or double

I want to write a template function that will work on both double and float, something like that:
template <typename T>
constexpr auto someCalc(const T x) {
return x * 4.0 + 3.0;
}
My issue is that both 4.0 and  3.0 are doubles literal, thus I get the following error on clang:
error: implicit conversion increases floating-point precision: 'const float' to 'double' [-Werror,-Wdouble-promotion]
Is there an elegant way to write this code without having the up-conversion to double? The best I can come up with, is this
template <typename T>
constexpr auto someCalc(const T x) {
constexpr T four = 4.0;
constexpr T three = 3.0;
return x * four + three;
}
which I find less readable and harder to maintain for larger/more complicated function.
I would do it this way:
template <typename T>
constexpr auto someCalc(const T x) {
return x * T(4.0) + T(3.0);
}
Or with static_cast, if you prefer it.
While HolyBlackCat's answer is completely viable, here's my two bits:
Your constants are supposed to mean something in that particular situation. They likely are magic numbers with some meaning. The best course of actions is to give them a name, if you want make them maintenable. And in newer C++ it allows them to be templates
#include <iostream>
namespace sdd // some_dirty_details
{
/// #brief: Description of the constant
template <class T>
constexpr T some_constant = static_cast<T>(3.0);
}
int main()
{
std::cout << sdd::some_constant<float> << std::endl;
}

Emulating the special properties of sizeof with constexpr

In C++ sizeof is somewhat unique in that it's legal to write this:
int x;
sizeof(x); // a variable
As well as simply:
sizeof(int); // a type
(There's a third even weirder variant I'd rather ignore for now though, with no parenthesis needed, since I'm pretty certain that is impossible to emulate)
I'd like to be able to replicate this behaviour myself. To motivate it I've got an example bitsof operator.
#include <climits>
template <typename T>
struct bits_traits {
enum { value = sizeof(T) * CHAR_BIT };
};
struct int_12_bit {
enum { bits = 12 };
// Let's pretent this has a bunch of code for looking and feeling like a 12bit int in a helpful and portable way
};
template <>
struct bits_traits<int_12_bit> {
enum { value = int_12_bit::bits };
};
#define bitsof(x) bits_traits<x>::value
int main() {
using std::size_t;
size_t b = bitsof(int);
size_t a = bitsof(int_12_bit);
int_12_bit x;
size_t c = bitsof(x); // <-- Not cool
}
Clearly I could have written the whole thing in terms of a macro, using sizeof, e.g.
#define bitsof(x) (sizeof(x) * CHAR_BIT)
But then I lose the ability to "specialise" it.
And equally I could write size_t c = bitsof(decltype(x)). However what I'm asking here is for a way of emulating that behaviour in my own code without having to settle for a workaround. How can I write a bitsof that looks and feels like sizeof, but specialises like traits? Do I just have to accept that sizeof is a bit special and live with it?
I initially played with a few ideas:
Perhaps decltype works like sizeof, e.g. decltype(0) and decltype(int) are synonymous. No luck there though.
Maybe we could do something with pointer/reference template parameters. I couldn't see a way of getting deduction to work properly for that case though, and it would impose additional constraints on what variables we could use bitsof with.
Maybe some crazy SFINAE with a combination of templates and macros, but I can't see a way of making that happen, it's always just a syntax error.
Possibly something to workaround the limitations of one of the above using GCC's statement-expr extension.
As there's an easy workaround with decltype and more of a learning experiment I'm open to ideas using anything available in any C++ released compiler targeting any past, present or future standard.
You can do something like this:
#include <type_traits>
#define bitsof(k) decltype(bitsof_left+(k)+bitsof_right)
template <class K>
struct bits_traits { /* whatever you want here */ };
struct bitsof_left_t {
template <class T>
bits_traits<T> operator+(const T&);
} bitsof_left;
struct bitsof_right_t {
template <class T>
friend T operator+(const T&, bitsof_right_t);
bitsof_right_t operator+();
template <class T>
operator T() const;
} bitsof_right;
int main()
{
using foo = bitsof(42);
using bar = bitsof(int);
static_assert(std::is_same<foo, bits_traits<int>>::value);
static_assert(std::is_same<bar, bits_traits<int>>::value);
}
It works like this.
a + (42) + b is parsed as (a + (42)) + b), then overloaded binary operator+ at either side kicks in. In my example the operators are only declared, not defined, but since it's unevaluated context, it doesn't matter.
a + (int) + b is parsed as a + ((int) (+ b)). Here we employ the overloaded unary + at the right side, then overloaded cast operator, then overloaded binary + at the left side.
Its hard and probably impossible, mainly because you can only pass compile-time constants as template values to templates, hence your last example with the int_12_bit x; will never be able to be a template value (and types can't be passed as parameters, of course). I played around a bit with decltype, declval and different templates, but I simply could not get it to take in types and (non-constand expression) values with a single "call". It's really unfortunate decltype doesn't accept types, I wonder why the committee choose to only accept expressions.
Since you mentioned gcc-extensions, there is an extension which can make it work, __typeof__.
I personally have never used this extension, but it seems like it works similar to decltype but it also accepts types directly.
This snipped compiles under gcc x86-64 8.3 for me:
template<typename T>
struct bits_trait;
template<>
struct bits_trait<int>{};
void f() {
int x;
bits_trait<__typeof__(x)>();
bits_trait<__typeof__(int)>();
}
But this will only compile under gcc.
Edit: Clang seems to support it as well, no luck with MSVC though.
Not considering macros and without decltype, it is simply not possible because of the language syntax.
However you can get pretty damn close:
template <class T>
constexpr auto bitsof(T) { return sizeof(T) * CHAR_BIT; }
template <>
constexpr auto bitsof(int_12_bit) { return 12; }
template <class T>
constexpr auto bitsof() { return sizeof(T) * CHAR_BIT; }
template <>
constexpr auto bitsof<int_12_bit>() { return 12; }
auto test()
{
constexpr int a{};
constexpr int_12_bit x{};
static_assert(bitsof(a) == 32);
static_assert(bitsof(x) == 12);
static_assert(bitsof<int>() == 32);
static_assert(bitsof<int_12_bit>() == 12);
}
Aside from the slightly different syntax (but c'mon it's so close it shouldn't really matter) the biggest difference to the sizeof is that the arguments are not in an unevaluated context. So bitsof(foo()) will call foo(). And bitsof(a) is UB if a is uninitialized.
Building upon the quite magical answer from n.m., with just tiny bit of massage, it seems it is possible to have bitsof mimic sizeof.
#include <climits>
#include <iostream>
#include <type_traits>
template <typename T>
struct bits_traits {
enum { value = sizeof(T) * CHAR_BIT };
};
struct int_12_bit {
enum { bits = 12 };
};
template <>
struct bits_traits<int_12_bit> {
enum { value = int_12_bit::bits };
};
#define bits_traits_of(k) decltype(bits_traits_of_left+(k)+bits_traits_of_right)
struct bits_traits_of_left_t {
template <class T>
bits_traits<T> operator+(const T&);
} bits_traits_of_left;
struct bits_traits_of_right_t {
template <class T>
friend T operator+(const T&, bits_traits_of_right_t);
bits_traits_of_right_t operator+();
template <class T>
operator T() const;
} bits_traits_of_right;
#define bitsof(x) bits_traits_of(x)::value
int main() {
using std::size_t;
size_t a = bitsof(int);
size_t b = bitsof(int_12_bit);
std::cout <<"a="<< a <<", b="<< b << std::endl;
int_12_bit x;
size_t c = bitsof(x);
std::cout <<"c="<< c << std::endl;
}
The only thing that I changed, other than adding in definitions for bits_traits, is to redefine bitsof so that it returns the bits_traits::value rather than the bits_traits type.
$ ./a.out
a=32, b=12
c=12
I'm just writing this up to verify that it can work. All credits should go to n.m.'s answer.

how to use the type of compile time constant primitive

How to use the type of a compile time constant primitive as type declaration for other variables?
I am trying to do some template metaprogramming in c++ for SI unit conversion. It comes down to how to automatically determine which primitive precision I need after one plus operator. For example:
template<typename Precision>
class Unit {
public:
Unit(Precision v) : value(v) {}
Precision value;
};
template<typename Precision1, typename Precision2>
struct PrecisionTransform {
constexpr static auto test = (Precision1)1 * (Precision2)1; // Compile time constant
using Type = Precision1; // TODO: ideally typeof(test)
};
template<typename Precision1, typename Precision2>
Unit<PrecisionTransform<Precision1, Precision2>::Type> operator+(const Unit<Precision1>& x, const Unit<Precision2>& y)
{
return Unit<PrecisionTransform<Precision1, Precision2>::Type>(x.value + y.value);
}
int main()
{
Unit<double> a = 2.0;
Unit<float> b = 1.0f;
auto c = a + b;
return 0;
}
or in simple terms, can some thing like this happen?
float a = 1;
typeof(a) b = 2;
It seems quite possible since I've gone this far. But I am not sure how to use
You almost got it. As max66 already pointed out, use decltype. First of all, you can replace your PrecisionTransform class with the follwing type alias (you have to #include <utility> for this):
template <typename Precision1, typename Precision2>
using TransformType = decltype(std::declval<Precision1>() * std::declval<Precision2>());
The std::declval<XYZ>() is just a more generic way of saying (Precision1)1 which allows you to also use types that don't have accessible constructors (in your case irrelevant as you only use primitives).
Your operator+ is then changed to:
template<typename Precision1, typename Precision2>
Unit<TransformType<Precision1, Precision2>> operator+(const Unit<Precision1>& x, const Unit<Precision2>& y)
{
return Unit<TransformType<Precision1, Precision2>>(x.value + y.value);
}
Note that you got a typo in your version of operator+ (both operands used Precision1).
As you can see here, the major compilers agree on this.

How to convert template classes?

I have following example:
struct Wrapper
{
virtual ~Wrapper()
{
}
template <typename U>
WrapperT<U> * clone()
{
return new WrapperT<U>(value); //will not work, because value is not known here
}
};
template <typename T>
struct WrapperT : Wrapper
{
explicit WrapperT(T v)
{
value = v;
}
T value;
};
and I want something like this:
Wrapper *t = new WrapperT<int>(1);
WrapperT<double> *t2 = t->clone<double>();
I know virtual templates are not available. Any ideas?
A possible approach is defining a visitor pattern, but the cost of implementing the visitor might be large if you want to support many different wrapped types (i.e. if it is not just a small subset).
Another problem you would get is that the conversions would be (have to be) dynamically dispatched, so they can fail at runtime and you would have to provide mechanisms to detect that and act on that then (exceptions come to mind). Nothing horrible...
The solution I propose is using a "neutral type" to make dynamically (as David Rodríguez - dribeas noted) the type conversion.
Advantage:
The solution is generic: you don't need to so any special thing when using a new type.
As drawbacks
Not good for performance.
Requires the insertion and extraction stream operators to be defined.
The code:
struct Wrapper
{
// get the "neutral type" value
virtual string getValue() const = 0;
template <typename U> Wrapper* clone() const;
};
template <typename T>
struct WrapperT: Wrapper
{
explicit WrapperT(T v): value(v)
{
}
virtual string getValue() const
{
// use streams to conversion to neutral value, but
// other better method would be suitable
ostringstream strm;
strm << value;
return strm.str();
}
T value;
};
template <typename U> Wrapper* Wrapper::clone() const {
U value;
istringstream strm(getValue());
strm >> value;
return new WrapperT<U>(value);
}
EDIT:
For a better performance solution, if only using numeric type, we can change string by a long double as "neutral type":
template <typename T>
double long WrapperT<T>::getValue() const
{
return value;
}
template <typename U> Wrapper* Wrapper::clone() const {
return new WrapperT<U>(getValue());
}
Do we want to avoid integral to floating point conversions when using only integral type? In that case, the solution will be a bit more complex:
create two getValue() virtual functions, one for integral and other one for floating point,
in clone() function select the desired getValue() function depending on U template parameter type (target type).