Force narrowing conversion warning but avoid narrowing int->double conversion warning

3 weeks ago 24
ARTICLE AD BOX

Similar to the problem described here I need to create a template class which should provide the conversion constructor from Any type. The conversion constructor should spot the narrowing conversions.

template<typename T> struct X { T v_; // Add conversion constructor here };

... so, the following code compiles without the errors and warnings:

// g++ -Wall -Werror -Werror=narrowing ./2.cpp #include <cstdint> #include <string_view> template<typename T> void test(X<T>) {} int main() { test<double>(1); test<std::string_view>("1"); }

The challenge is I want the conversion constructor to be silent on int -> double conversion when input is a constant expression as described in the C++ Standard:

[dcl.init.list]

{7} A narrowing conversion is an implicit conversion

7.3) from an integer type or unscoped enumeration type to a floating-point type, except where the source is a constant expression and the actual value after conversion will fit into the target type and will produce the original value when converted back to the original type, or

In case I define the conversion constructor like following:

X(T v) : v_(v) {}

... it works just great if T == double but it does not work if T == string_view and the input parameter type is char const*

./2.cpp:26:32: error: could not convert ‘(const char*)"1"’ from ‘const char*’ to ‘X<std::basic_string_view<char> >’ 26 | test<std::string_view>("1");

In case I define that constructor like following:

template<typename Other> X(Other const& v) : v_{v} {}

...it works great with the std::string_view but emits the narrowing conversion warning if T == double and the type of the input argument is int:

./2.cpp:17:23: error: narrowing conversion of ‘(int)v’ from ‘int’ to ‘double’ [-Werror=narrowing] 17 | X(Other const& v) : v_{v} {} | ^~~~~

Neither of the following answer my question:

template deduction and implicit constructors: Is there a way to make template deduction work with implicit conversion?

How to use template function for implicit conversion

Narrowing conversion from char to double

One option I see is to declare two constructors:

One for the case when T is a floating point type

Another one for the rest of the cases.

... but it seems it is an overkill.

Another option is to declare one constructor and enable_if_t it if OtherT can be converted into the T without the data loss. I just have to come with the such trait function:

template<typename Other, typename = std::enable_if_t<!IsNarrowingConversion<Other, T>>> X(Other const& v) : v_(static_cast<T>(v)) {}

In this case hard error will be reported instead of warning, which is ok in my case.

Are there other options?

Read Entire Article