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:
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?
