I want to write a class template, which:
A<float>
have just a member variable val
;A<int>
have a member variable val
and a member function make_unsigned
(return unsigned
).I want to explicitly state the return value of make_unsigned
. Here is my code.
#include <concepts>
template<typename T> struct A
{
T val;
std::make_unsigned_t<T> make_unsigned() requires std::signed_integral<T>
{
return static_cast<std::make_unsigned<T>::type>(val);
}
};
int main()
{
A<float> val;
return 0;
}
Also I have tried auto make_unsigned() requires std::signed_integral<T> -> std::make_unsigned_t<T>
and auto make_unsigned() -> std::make_unsigned_t<T> requires std::signed_integral<T>
, but all of them cannot be compiled. It complains:
~ LANG=C g++ main.cpp -std=c++20 -o main
In file included from /usr/include/c++/10.2.0/bits/move.h:57,
from /usr/include/c++/10.2.0/bits/stl_pair.h:59,
from /usr/include/c++/10.2.0/utility:70,
from /usr/include/c++/10.2.0/array:38,
from main.cpp:1:
/usr/include/c++/10.2.0/type_traits: In instantiation of ‘struct std::make_unsigned<float>’:
/usr/include/c++/10.2.0/type_traits:1965:11: required by substitution of ‘template<class _Tp> using make_unsigned_t = typename std::make_unsigned::type [with _Tp = float]’
main.cpp:8:29: required from ‘struct A<float>’
main.cpp:17:14: required from here
/usr/include/c++/10.2.0/type_traits:1826:62: error: invalid use of incomplete type ‘class std::__make_unsigned_selector<float, false, false>’
1826 | { typedef typename __make_unsigned_selector<_Tp>::__type type; };
| ^~~~
/usr/include/c++/10.2.0/type_traits:1733:11: note: declaration of ‘class std::__make_unsigned_selector<float, false, false>’
1733 | class __make_unsigned_selector;
Or:
~ LANG=C g++ main.cpp -std=c++20 -o main
main.cpp:8:59: error: base operand of ‘->’ is not a pointer
8 | auto make_unsigned() requires std::signed_integral<T> -> std::make_unsigned_t<T>
| ^~
main.cpp:8:62: error: invalid use of ‘using make_unsigned_t = typename std::make_unsigned<_Tp>::type’
8 | auto make_unsigned() requires std::signed_integral<T> -> std::make_unsigned_t<T>
| ^~~
cc1plus: error: expression must be enclosed in parenthese
Or:
~ LANG=C g++ main.cpp -std=c++20 -o main
In file included from /usr/include/c++/10.2.0/bits/move.h:57,
from /usr/include/c++/10.2.0/bits/stl_pair.h:59,
from /usr/include/c++/10.2.0/utility:70,
from /usr/include/c++/10.2.0/array:38,
from main.cpp:1:
/usr/include/c++/10.2.0/type_traits: In instantiation of ‘struct std::make_unsigned<float>’:
/usr/include/c++/10.2.0/type_traits:1965:11: required by substitution of ‘template<class _Tp> using make_unsigned_t = typename std::make_unsigned::type [with _Tp = float]’
main.cpp:8:10: required from ‘struct A<float>’
main.cpp:17:14: required from here
/usr/include/c++/10.2.0/type_traits:1826:62: error: invalid use of incomplete type ‘class std::__make_unsigned_selector<float, false, false>’
1826 | { typedef typename __make_unsigned_selector<_Tp>::__type type; };
| ^~~~
/usr/include/c++/10.2.0/type_traits:1733:11: note: declaration of ‘class std::__make_unsigned_selector<float, false, false>’
1733 | class __make_unsigned_selector;
How can I do it?
Member functions are operators and functions that are declared as members of a class. Member functions do not include operators and functions declared with the friend specifier. These are called friends of a class. You can declare a member function as static ; this is called a static member function.
If a member function's definition is outside the class declaration, it is treated as an inline function only if it is explicitly declared as inline . In addition, the function name in the definition must be qualified with its class name using the scope-resolution operator ( :: ).
Private: The class members declared as private can be accessed only by the member functions inside the class. They are not allowed to be accessed directly by any object or function outside the class. Only the member functions or the friend functions are allowed to access the private data members of the class.
std::make_unsigned
is not SFINAE friendly, so you have to
don't be explicit on return type, use auto
/decltype(auto)
:
auto make_unsigned() requires std::signed_integral<T>
{
return static_cast<std::make_unsigned<T>::type>(val);
}
add a "friendly" trait (a trait which doesn't make the program ill-formed with invalid type), and additionally use a return type (as function is not template, no SFINAE here):
template <typename T>
struct make_unsigned_or_self
{
using type = T;
};
template <typename T>
using make_unsigned_or_self_t = typename make_unsigned_or_self<T>::type;
template <std::signed_integral T>
struct make_unsigned_or_self<T>
{
using type = std::make_unsigned_t<T>;
};
and then
make_unsigned_or_self_t<T> make_unsigned() requires std::signed_integral<T>
{
return static_cast<std::make_unsigned<T>::type>(val);
}
Demo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With