ูƒูŠููŠุฉ ุฌุนู„ SFINAE ุฃู†ูŠู‚ ูˆู…ูˆุซูˆู‚

ู…ุฑุญุจุง ู…ุฑุฉ ุงุฎุฑู‰ ุฅู†ู†ุง ู†ุดุงุฑูƒูƒ ู…ู‚ุงู„ุฉ ู…ุซูŠุฑุฉ ู„ู„ุงู‡ุชู…ุงู… ุŒ ุชู… ุฅุนุฏุงุฏ ุชุฑุฌู…ุฉ ู„ู‡ุง ุฎุตูŠุตู‹ุง ู„ุทู„ุงุจ ุงู„ุฏูˆุฑุฉ ุงู„ุชุฏุฑูŠุจูŠุฉ "C ++ Developer" .





ุงู„ูŠูˆู… ู„ุฏูŠู†ุง ู…ู†ุดูˆุฑ ุถูŠู ู…ู† ู‚ุจู„ MADdรกm Balรกzs. ุขุฏู… ู‡ูˆ ู…ู‡ู†ุฏุณ ุจุฑู…ุฌูŠุงุช ููŠ Verizon Smart Communities Hungary ูˆูŠุทูˆุฑ ุชุญู„ูŠู„ุงุช ุงู„ููŠุฏูŠูˆ ู„ู„ุฃู†ุธู…ุฉ ุงู„ู…ุฏู…ุฌุฉ. ุฃุญุฏ ุดุบูู‡ ู‡ูˆ ุชุญุณูŠู† ูˆู‚ุช ุงู„ุชุฌู…ูŠุน ุŒ ู„ุฐู„ูƒ ูˆุงูู‚ ุนู„ู‰ ุงู„ููˆุฑ ุนู„ู‰ ูƒุชุงุจุฉ ู…ู†ุดูˆุฑ ุถูŠู ุญูˆู„ ู‡ุฐุง ุงู„ู…ูˆุถูˆุน. ูŠู…ูƒู†ูƒ ุฃู† ุชุฌุฏ ุขุฏู… ุนู„ู‰ ุงู„ุฅู†ุชุฑู†ุช ุนู„ู‰ LinkedIn .

ููŠ ุณู„ุณู„ุฉ ู…ู† ุงู„ู…ู‚ุงู„ุงุช ุญูˆู„ ูƒูŠููŠุฉ ุฌุนู„ SFINAE ุฃู†ูŠู‚ุฉ ุŒ ุดุงู‡ุฏู†ุง ูƒูŠููŠุฉ ุฌุนู„ ู‚ุงู„ุจ SFINAE ุฎุงุต ุจู†ุง ู…ูˆุฌุฒุง ูˆู…ุนุจุฑุง.

ู…ุฌุฑุฏ ุฅู„ู‚ุงุก ู†ุธุฑุฉ ุนู„ู‰ ุดูƒู„ู‡ ุงู„ุฃุตู„ูŠ:

template<typename T> class MyClass { public: void MyClass(T const& x){} template<typename T_ = T> void f(T&& x, typename std::enable_if<!std::is_reference<T_>::value, std::nullptr_t>::type = nullptr){} }; 


ูˆู…ู‚ุงุฑู†ุชู‡ุง ู…ุน ู‡ุฐุง ุงู„ุดูƒู„ ุงู„ุฃูƒุซุฑ ุชุนุจูŠุฑุง:

 template<typename T> using IsNotReference = std::enable_if_t<!std::is_reference_v<T>>; template<typename T> class MyClass { public: void f(T const& x){} template<typename T_ = T, typename = IsNotReference <T_>> void f(T&& x){} }; 

ูŠู…ูƒู†ู†ุง ุฃู† ู†ุนุชู‚ุฏ ุจุดูƒู„ ู…ุนู‚ูˆู„ ุฃู†ู‡ ู…ู† ุงู„ู…ู…ูƒู† ุจุงู„ูุนู„ ุงู„ุงุณุชุฑุฎุงุก ูˆุงู„ุจุฏุก ููŠ ุงุณุชุฎุฏุงู…ู‡ ููŠ ุงู„ุฅู†ุชุงุฌ. ูŠู…ูƒู†ู†ุง ุฐู„ูƒ ุŒ ุฅู†ู‡ ูŠุนู…ู„ ููŠ ู…ุนุธู… ุงู„ุญุงู„ุงุช ุŒ ู„ูƒู† - ูƒู…ุง ู†ุชุญุฏุซ ุนู† ุงู„ูˆุงุฌู‡ุงุช - ูŠุฌุจ ุฃู† ูŠูƒูˆู† ูƒูˆุฏู†ุง ุขู…ู†ู‹ุง ูˆู…ูˆุซูˆู‚ู‹ุง ุจู‡. ู‡ู„ ู‡ุฐุง ุตุญูŠุญุŸ ุฏุนูˆู†ุง ู†ุญุงูˆู„ ุงุฎุชุฑุงู‚ู‡!

ุงู„ุนูŠุจ ุฑู‚ู… 1: ูŠู…ูƒู† ุชุฌุงูˆุฒ SFINAE


ุนุงุฏุฉ ุŒ ูŠุชู… ุงุณุชุฎุฏุงู… SFINAE ู„ุชุนุทูŠู„ ุฌุฒุก ู…ู† ุงู„ูƒูˆุฏ ุญุณุจ ุงู„ุญุงู„ุฉ. ูŠู…ูƒู† ุฃู† ูŠูƒูˆู† ู‡ุฐุง ู…ููŠุฏู‹ุง ู„ู„ุบุงูŠุฉ ุฅุฐุง ุงุญุชุฌู†ุง ุฅู„ู‰ ุชู†ููŠุฐ ุŒ ุนู„ู‰ ุณุจูŠู„ ุงู„ู…ุซุงู„ ุŒ ูˆุธูŠูุฉ abs ุงู„ู…ุนุฑูุฉ ู…ู† ู‚ุจู„ ุงู„ู…ุณุชุฎุฏู… ู„ุณุจุจ ู…ุง (ูุฆุฉ ุงู„ุญุณุงุจ ุงู„ู…ุนุฑูุฉ ู…ู† ู‚ุจู„ ุงู„ู…ุณุชุฎุฏู… ุŒ ูˆุงู„ุชุญุณูŠู† ู„ู…ุนุฏุงุช ู…ุนูŠู†ุฉ ุŒ ู„ุฃุบุฑุงุถ ุงู„ุชุฏุฑูŠุจ ุŒ ูˆู…ุง ุฅู„ู‰ ุฐู„ูƒ):

 template< typename T > T myAbs( T val ) { return( ( val <= -1 ) ? -val : val ); } int main() { int a{ std::numeric_limits< int >::max() }; std::cout << "a: " << a << " myAbs( a ): " << myAbs( a ) << std::endl; } 

ูŠุนุฑุถ ู‡ุฐุง ุงู„ุจุฑู†ุงู…ุฌ ู…ุง ูŠู„ูŠ ุŒ ูˆุงู„ุฐูŠ ูŠุจุฏูˆ ุทุจูŠุนูŠุงู‹ ุชู…ุงู…ู‹ุง:

 a: 2147483647 myAbs( a ): 2147483647 

ูˆู„ูƒู† ูŠู…ูƒู†ู†ุง ุงุณุชุฏุนุงุก ุฏุงู„ุฉ abs ุจู†ุง ุจุงุณุชุฎุฏุงู… ุงู„ูˆุณุงุฆุท ุบูŠุฑ ุงู„ู…ูˆู‚ุนุฉ T ุŒ ูˆุณูŠูƒูˆู† ุงู„ุชุฃุซูŠุฑ ูƒุงุฑุซูŠู‹ุง:

 nt main() { unsigned int a{ std::numeric_limits< unsigned int >::max() }; std::cout << "a: " << a << " myAbs( a ): " << myAbs( a ) << std::endl; } 

ููŠ ุงู„ูˆุงู‚ุน ุŒ ูŠุนุฑุถ ุงู„ุจุฑู†ุงู…ุฌ ุงู„ุขู†:

a: 4294967295 myAbs( a ): 1

ู„ู… ูŠุชู… ุชุตู…ูŠู… ูˆุธูŠูุชู†ุง ู„ู„ุนู…ู„ ู…ุน ุงู„ูˆุณุงุฆุท ุบูŠุฑ ุงู„ู…ูˆู‚ุนุฉ ุŒ ู„ุฐู„ูƒ ูŠุฌุจ ุนู„ูŠู†ุง ุชู‚ูŠูŠุฏ ุงู„ู…ุฌู…ูˆุนุฉ ุงู„ู…ุญุชู…ู„ุฉ ู…ู† T ู…ุน SFINAE:

 template< typename T > using IsSigned = std::enable_if_t< std::is_signed_v< T > >; template< typename T, typename = IsSigned< T > > T myAbs( T val ) { return( ( val <= -1 ) ? -val : val ); } 

ูŠุนู…ู„ ุงู„ุฑู…ุฒ ูƒู…ุง ู‡ูˆ ู…ุชูˆู‚ุน: ูŠุคุฏูŠ ุงุณุชุฏุนุงุก myAbs ุจู†ูˆุน ุบูŠุฑ ู…ูˆู‚ู‘ุน ุฅู„ู‰ ุญุฏูˆุซ ุฎุทุฃ ูˆู‚ุช ุงู„ุชุฑุฌู…ุฉ:

candidate template ignored: requirement 'std::is_signed_v< unsigned int>' was not satisfied [with T = unsigned int]

ุงู„ู‚ุฑุตู†ุฉ SFINAE ุงู„ุฏูˆู„ุฉ


ุซู… ู…ุง ู‡ูˆ ุงู„ุฎุทุฃ ููŠ ู‡ุฐู‡ ุงู„ูˆุธูŠูุฉุŸ ู„ู„ุฅุฌุงุจุฉ ุนู„ู‰ ู‡ุฐุง ุงู„ุณุคุงู„ ุŒ ู†ุญุชุงุฌ ุฅู„ู‰ ุงู„ุชุญู‚ู‚ ู…ู† ูƒูŠููŠุฉ ู‚ูŠุงู… myAbs ุจุชู†ููŠุฐ SFINAE.

 template< typename T, typename = IsSigned<T> > T myAbs( T val ); 

myAbs ู‡ูˆ ู‚ุงู„ุจ ูˆุธูŠูุฉ ู…ุน ู†ูˆุนูŠู† ู…ู† ู…ุนู„ู…ุงุช ู‚ุงู„ุจ ุงู„ุฅุฏุฎุงู„. ุงู„ุฃูˆู„ ู‡ูˆ ุงู„ู†ูˆุน ุงู„ูุนู„ูŠ ู„ู„ูˆุณูŠุทุฉ ุงู„ุฏุงู„ุฉ ุŒ ูˆุงู„ุซุงู†ูŠ ู‡ูˆ IsSigned < T > ุงู„ุงูุชุฑุงุถูŠ (ูˆุฅู„ุง std::enable_if_t < std::is_signed_v < T > > ุฃูˆ std::enable_if < std::is_signed_v < T>, void>::type ุŒ ูˆู‡ูˆ ุจุฏูŠู„ void ุฃูˆ ูุงุดู„).

ูƒูŠู ูŠู…ูƒู† ุฃู† ู†ุณู…ูŠ myAbs ุŸ ู‡ู†ุงูƒ 3 ุทุฑู‚:

 int a{ myAbs( -5 ) }; int b{ myAbs< int >( -5 ) }; int c{ myAbs< int, void >( -5 ) }; 

ุงู„ู…ูƒุงู„ู…ุงุช ุงู„ุฃูˆู„ู‰ ูˆุงู„ุซุงู†ูŠุฉ ูˆุงุถุญุฉ ูˆู…ุจุงุดุฑุฉ ุŒ ูˆู„ูƒู† ุงู„ุซุงู„ุซุฉ ู…ุซูŠุฑุฉ ู„ู„ุงู‡ุชู…ุงู…: ู…ุง ู‡ูŠ ุญุฌุฉ ุงู„ู‚ุงู„ุจ void ุŸ

ู…ุนู„ู…ุฉ ุงู„ู‚ุงู„ุจ ุงู„ุซุงู†ูŠ ู‡ูŠ ู…ุฌู‡ูˆู„ุฉ ุŒ ูˆู„ู‡ุง ู†ูˆุน ุงูุชุฑุงุถูŠ ุŒ ู„ูƒู†ู‡ุง ู„ุง ุชุฒุงู„ ู…ุนู„ู…ุฉ ู‚ุงู„ุจ ุŒ ู„ุฐู„ูƒ ูŠู…ูƒู†ูƒ ุชุญุฏูŠุฏู‡ุง ุจุดูƒู„ ุตุฑูŠุญ. ู‡ู„ ู‡ุฐู‡ ู…ุดูƒู„ุฉุŸ ููŠ ู‡ุฐู‡ ุงู„ุญุงู„ุฉ ุŒ ู‡ุฐู‡ ู…ุดูƒู„ุฉ ูƒุจูŠุฑุฉ ุญู‚ู‹ุง. ูŠู…ูƒู†ู†ุง ุงุณุชุฎุฏุงู… ุงู„ู†ู…ูˆุฐุฌ ุงู„ุซุงู„ุซ ู„ู„ุชุฌูˆู„ ููŠ ุณูŠููŠู†ุง

 unsigned int d{ myAbs< unsigned int, void >( 5u ) }; unsigned int e{ myAbs< unsigned int, void >( std::numeric_limits< unsigned int >::max() ) }; 

ูŠุฌู…ุน ู‡ุฐุง ุงู„ุฑู…ุฒ ุจุดูƒู„ ุฌูŠุฏ ุŒ ูˆู„ูƒู†ู‡ ูŠุคุฏูŠ ุฅู„ู‰ ู†ุชุงุฆุฌ ูƒุงุฑุซูŠุฉ ุŒ ู„ุชุฌู†ุจ ู…ุง ุงุณุชุฎุฏู…ู†ุงู‡ SFINAE:

 a: 4294967295 myAbs( a ): 1 

ุณู†ุญู„ ู‡ุฐู‡ ุงู„ู…ุดูƒู„ุฉ - ู„ูƒู† ุฃูˆู„ุงู‹: ู‡ู„ ู‡ู†ุงูƒ ุฃูŠ ุนูŠูˆุจ ุฃุฎุฑู‰ุŸ ุญุณู†ุง ...

ุงู„ุนูŠุจ ุฑู‚ู… 2: ู„ุง ูŠู…ูƒู†ู†ุง ุชู†ููŠุฐ ุชุทุจูŠู‚ุงุช ู…ุญุฏุฏุฉ


ุงู„ุงุณุชุฎุฏุงู… ุงู„ุดุงุฆุน ุงู„ุขุฎุฑ ู„ู€ SFINAE ู‡ูˆ ุชูˆููŠุฑ ุชุทุจูŠู‚ุงุช ู…ุญุฏุฏุฉ ู„ุธุฑูˆู ูˆู‚ุช ุงู„ุชุฑุฌู…ุฉ ุงู„ู…ุญุฏุฏุฉ. ู…ุงุฐุง ู„ูˆ ูƒู†ุง ู„ุง ู†ุฑูŠุฏ ุญุธุฑ ุฏุนูˆุฉ myAbs ุจู‚ูŠู… myAbs ูˆุชู‚ุฏูŠู… ุชุทุจูŠู‚ ุชุงูู‡ ู„ู‡ุฐู‡ ุงู„ุญุงู„ุงุชุŸ ูŠู…ูƒู†ู†ุง ุงุณุชุฎุฏุงู… if constexpr ููŠ C ++ 17 (ุณู†ู†ุงู‚ุด ู‡ุฐุง ู„ุงุญู‚ู‹ุง) ุŒ ุฃูˆ ูŠู…ูƒู†ู†ุง:

  template< typename T > using IsSigned = std::enable_if_t< std::is_signed_v< T > >; template< typename T > using IsUnsigned = std::enable_if_t< std::is_unsigned_v< T > >; template< typename T, typename = IsSigned< T > > T myAbs( T val ) { return( ( val <= -1 ) ? -val : val ); } template< typename T, typename = IsUnsigned< T > > T myAbs( T val ) { return val; } 

ู„ูƒู† ู…ุง ู‡ุฐุงุŸ

 error: template parameter redefines default argument template< typename T, typename = IsUnsigned< T > > note: previous default template argument defined here template< typename T, typename = IsSigned< T > > 

ุฃูˆู‡ ุŒ ูŠู†ุต ู…ุนูŠุงุฑ C ++ (C ++ 17 ุ› ยง 17.1.16) ุนู„ู‰ ู…ุง ูŠู„ูŠ :

"ู„ุง ูŠู†ุจุบูŠ ุชู‚ุฏูŠู… ุงู„ูˆุณุงุฆุท ุงู„ุงูุชุฑุงุถูŠุฉ ู„ู…ุนู„ู…ุฉ ุงู„ู‚ุงู„ุจ ุจูˆุงุณุทุฉ ุฅุนู„ุงู†ูŠู† ู…ุฎุชู„ููŠู† ููŠ ู†ูุณ ุงู„ู†ุทุงู‚."

ุนููˆู‹ุง ุŒ ู‡ุฐุง ุจุงู„ุถุจุท ู…ุง ูุนู„ู†ุงู‡ ...

ู„ู…ุงุฐุง ู„ุง ุชุณุชุฎุฏู… ุงู„ุนุงุฏูŠุฉ ุฅุฐุงุŸ


ูŠู…ูƒู† ุฃู† ู†ุณุชุฎุฏู…ู‡ุง ูู‚ุท ููŠ ูˆู‚ุช ุงู„ุชุดุบูŠู„:

 template< typename T > T myAbs( T val ) { if( std::is_signed_v< T > ) { return ( ( val <= -1 ) ? -val : val ); } else { return val; } } 

ุณูŠู‚ูˆู… ุงู„ู…ุญูˆู„ ุงู„ุจุฑู…ุฌูŠ ุจุชุญุณูŠู† ุงู„ุดุฑุท ู„ุฃู†ู‡ if (std::is_signed_v < T>) if (true) ุฃูˆ if (false) ุจุนุฏ ุฅู†ุดุงุก ุงู„ู‚ุงู„ุจ. ู†ุนู… ุŒ ู…ุน ุชุทุจูŠู‚ู†ุง ุงู„ุญุงู„ูŠ ู„ myAbs ู‡ุฐุง ุณูˆู ูŠู†ุฌุญ. ู„ูƒู† ุจุดูƒู„ ุนุงู… ุŒ ูŠูุฑุถ ู‡ุฐุง ู‚ูŠูˆุฏู‹ุง ู‡ุงุฆู„ุฉ: ูŠุฌุจ ุฃู† ุชูƒูˆู† else if ูˆ else ุตุงู„ุญุฉ ู„ูƒู„ T ู…ุงุฐุง ู„ูˆ ู‚ู…ู†ุง ุจุชุบูŠูŠุฑ ุชุทุจูŠู‚ู†ุง ู‚ู„ูŠู„ุงู‹:

 template< typename T > T myAbs( T val ) { if( std::is_signed_v< T > ) { return std::abs( val ); } else { return val; } } int main() { unsigned int a{ myAbs( 5u ) }; } 

ุณูˆู ูŠุชุนุทู„ ูƒูˆุฏู†ุง ุนู„ู‰ ุงู„ููˆุฑ:

 error: call of overloaded 'abs(unsigned int&)' is ambiguous 

ู‡ุฐุง ุงู„ุชู‚ูŠูŠุฏ ู‡ูˆ ู…ุง ูŠุญุฐูู‡ SFINAE: ูŠู…ูƒู†ู†ุง ูƒุชุงุจุฉ ุฑู…ุฒ ุตุงู„ุญ ูู‚ุท ู„ู…ุฌู…ูˆุนุฉ ูุฑุนูŠุฉ ู…ู† T (ููŠ myAbs ุŒ ูŠูƒูˆู† ุตุงู„ุญู‹ุง ู„ู„ุฃู†ูˆุงุน ุบูŠุฑ ุงู„ู…ูˆู‚ุนุฉ ูู‚ุท ุฃูˆ ุตุงู„ุญู‹ุง ู„ู„ุฃู†ูˆุงุน ุงู„ู…ูˆู‚ุนุฉ ูู‚ุท).

ุงู„ุญู„: ู†ู…ูˆุฐุฌ ุขุฎุฑ ู„ู€ SFINAE


ู…ุงุฐุง ูŠู…ูƒู†ู†ุง ุฃู† ู†ูุนู„ ู„ู„ุชุบู„ุจ ุนู„ู‰ ู‡ุฐู‡ ุงู„ุนูŠูˆุจุŸ ุจุงู„ู†ุณุจุฉ ู„ู„ู…ุดูƒู„ุฉ ุงู„ุฃูˆู„ู‰ ุŒ ูŠุฌุจ ุนู„ูŠู†ุง ูุฑุถ ุงุฎุชุจุงุฑ SFINAE ุงู„ุฎุงุต ุจู†ุง ุจุบุถ ุงู„ู†ุธุฑ ุนู† ูƒูŠููŠุฉ ุงุณุชุฏุนุงุก ุงู„ู…ุณุชุฎุฏู…ูŠู† ู„ูˆุธุงุฆูู†ุง. ุญุงู„ูŠู‹ุง ุŒ ูŠู…ูƒู† ุงู„ุชุญุงูŠู„ ุนู„ู‰ ุงุฎุชุจุงุฑู†ุง ุนู†ุฏู…ุง ู„ุง ูŠุญุชุงุฌ ุงู„ู…ุชุฑุฌู… ุฅู„ู‰ ุงู„ู†ูˆุน ุงู„ุงูุชุฑุงุถูŠ ู„ู…ุนู„ู…ุฉ ุงู„ู‚ุงู„ุจ ุงู„ุซุงู†ูŠ.

ู…ุงุฐุง ู„ูˆ ุงุณุชุฎุฏู…ู†ุง ูƒูˆุฏ SFINAE ู„ู„ุฅุนู„ุงู† ุนู† ู†ูˆุน ู…ุนู„ู…ุฉ ู‚ุงู„ุจ ุจุฏู„ุงู‹ ู…ู† ุชู‚ุฏูŠู… ู†ูˆุน ุงูุชุฑุงุถูŠุŸ ู„ู†ุฌุฑุจ:

 template< typename T > using IsSigned = std::enable_if_t< std::is_signed_v< T >, bool >; template< typename T, IsSigned< T > = true > T myAbs( T val ) { return( ( val <= -1 ) ? -val : val ); } int main() { //int a{ myAbs( 5u ) }; int b{ myAbs< int >( 5u ) }; //int c{ myAbs< unsigned int, true >( 5u ) }; } 

ู†ุญุชุงุฌ ุฅู„ู‰ ุฃู† ูŠูƒูˆู† IsSigned ู†ูˆุนู‹ุง ุขุฎุฑ ุบูŠุฑ ุงู„ูุฑุงุบ ููŠ ุงู„ุญุงู„ุงุช ุงู„ุตุญูŠุญุฉ ุŒ ู„ุฃู†ู†ุง ู†ุฑูŠุฏ ุชู‚ุฏูŠู… ู‚ูŠู…ุฉ ุงูุชุฑุงุถูŠุฉ ู„ู‡ุฐุง ุงู„ู†ูˆุน. ู„ุง ุชูˆุฌุฏ ู‚ูŠู…ุฉ ู„ู„ู†ูˆุน ุงู„ูุงุฑุบ ุŒ ู„ุฐู„ูƒ ูŠุฌุจ ุนู„ูŠู†ุง ุงุณุชุฎุฏุงู… ุดูŠุก ุขุฎุฑ: bool ุŒ int ุŒ enum ุŒ nullptr_t ุŒ ุฅู„ุฎ. ุนุงุฏุฉู‹ ู…ุง ุฃุณุชุฎุฏู… bool - ููŠ ู‡ุฐู‡ ุงู„ุญุงู„ุฉ ุŒ ุชุจุฏูˆ ุงู„ุชุนุจูŠุฑุงุช ุฐุงุช ู…ุนู†ู‰:

 template< typename T, IsSigned< T > = true > 

ุฅู†ู‡ ูŠุนู…ู„! ุจุงู„ู†ุณุจุฉ ุฅู„ู‰ myAbs (5u) ูŠู„ู‚ูŠ ุงู„ู…ุชุฑุฌู… ุฎุทุฃ ุŒ ูƒู…ุง ูƒุงู† ู…ู† ู‚ุจู„:

 candidate template ignored: requirement 'std::is_signed_v<unsigned int>' was not satisfied [with T = unsigned int 

ุงู„ู…ูƒุงู„ู…ุฉ ุงู„ุซุงู†ูŠุฉ ุŒ myAbs < int> (5u) ู„ุง ุชุฒุงู„ ุตุงู„ุญุฉ ุŒ ูู†ุญู† ู†ู‚ูˆู„ ู„ู†ูˆุน ุงู„ู…ุญูˆู„ ุงู„ุจุฑู…ุฌูŠ T ุตุฑุงุญุฉ ุŒ ู„ุฐู„ูƒ ูŠุญูˆู„ 5u ุฅู„ู‰ int .

ุฃุฎูŠุฑู‹ุง ุŒ ู„ู… ูŠุนุฏ ุจุฅู…ูƒุงู†ู†ุง ุชุชุจุน myAbs ุญูˆู„ ุงู„ุฅุตุจุน: myAbs < unsigned int, true> (5u) ูŠู„ู‚ูŠ ุฎุทุฃ. ู„ุง ูŠู‡ู… ุฅุฐุง ู‚ุฏู…ู†ุง โ€‹โ€‹ู‚ูŠู…ุฉ ุงูุชุฑุงุถูŠุฉ ููŠ ุงู„ู…ูƒุงู„ู…ุฉ ุฃู… ู„ุง ุŒ ูŠุชู… ุชู‚ูŠูŠู… ุฌุฒุก ู…ู† ุชุนุจูŠุฑ SFINAE ุนู„ู‰ ุฃูŠ ุญุงู„ ุŒ ู„ุฃู† ุงู„ู…ุชุฑุฌู… ูŠุญุชุงุฌ ุฅู„ู‰ ู†ูˆุน ูˆุณูŠุทุฉ ู…ู† ู‚ูŠู…ุฉ ู‚ุงู„ุจ ู…ุฌู‡ูˆู„ุฉ.

ูŠู…ูƒู†ู†ุง ุงู„ุงู†ุชู‚ุงู„ ุฅู„ู‰ ุงู„ู…ุดูƒู„ุฉ ุงู„ุชุงู„ูŠุฉ - ู„ูƒู† ุงู†ุชุธุฑ ู„ุญุธุฉ! ุฃุนุชู‚ุฏ ุฃู†ู†ุง ู„ู… ู†ุนุฏ ู†ุชุฌุงูˆุฒ ุงู„ูˆุณูŠุทุฉ ุงู„ุงูุชุฑุงุถูŠุฉ ู„ู…ุนู„ู…ุฉ ุงู„ู‚ุงู„ุจ ู†ูุณู‡ุง ุŒ ูู…ุง ู‡ูˆ ุงู„ู…ูˆู‚ู ุงู„ุฃุตู„ูŠุŸ

 template< typename T, typename = IsUnsigned< T > > T myAbs( T val ); template< typename T, typename = IsSigned< T > > T myAbs( T val ); 

ูˆู„ูƒู† ุงู„ุขู† ู…ุน ุงู„ูƒูˆุฏ ุงู„ุญุงู„ูŠ:

 template< typename T, IsUnsigned< T > = true > T myAbs( T val ); template< typename T, IsSigned< T > = true > T myAbs( T val ); 

ูŠุจุฏูˆ ู…ุดุงุจู‡ุงู‹ ู„ู„ุบุงูŠุฉ ู„ู„ุฑู…ุฒ ุงู„ุณุงุจู‚ ุŒ ู„ุฐู„ูƒ ู‚ุฏ ู†ุนุชู‚ุฏ ุฃู† ู‡ุฐุง ู„ู† ูŠู†ุฌุญ ุฃูŠุถู‹ุง ุŒ ูˆู„ูƒู† ููŠ ุงู„ุญู‚ูŠู‚ุฉ ู‡ุฐุง ุงู„ุฑู…ุฒ ู„ุง ูŠูˆุงุฌู‡ ู†ูุณ ุงู„ู…ุดูƒู„ุฉ. ู…ุง ู‡ูˆ IsUnsigned < T> ุŸ ู…ู†ุทู‚ูŠ ุฃูˆ ูุดู„ ุงู„ุจุญุซ. ูˆู…ุง ู‡ูˆ IsSigned < T> ุŸ ู†ูุณ ุงู„ุดูŠุก ุŒ ูˆู„ูƒู† ุฅุฐุง ูƒุงู† ุฃุญุฏู‡ู… Bool ุŒ ูุฅู† ุงู„ุขุฎุฑ ู‡ูˆ ุนู…ู„ูŠุฉ ุจุญุซ ูุงุดู„ุฉ.

ู‡ุฐุง ูŠุนู†ูŠ ุฃู†ู†ุง ู„ุง ู†ุชุฌุงูˆุฒ ุงู„ูˆุณูŠุทุงุช ุงู„ุงูุชุฑุงุถูŠุฉ ุŒ ู†ุธุฑู‹ุง ู„ูˆุฌูˆุฏ ุฏุงู„ุฉ ูˆุงุญุฏุฉ ูู‚ุท ู…ุน bool ูˆุณูŠุทุฉ ุงู„ู‚ุงู„ุจ ุŒ ูˆุงู„ุขุฎุฑ ุจุฏูŠู„ ูุงุดู„ ุŒ ู„ุฐู„ูƒ ู„ุง ูˆุฌูˆุฏ ู„ู‡.

ุงู„ุณูƒุฑ ุงู„ู†ุญูˆูŠ


UPD. ุชู… ุญุฐู ู‡ุฐู‡ ุงู„ูู‚ุฑุฉ ู…ู† ู‚ุจู„ ุงู„ู…ุคู„ู ุจุณุจุจ ูˆุฌูˆุฏ ุฃุฎุทุงุก ููŠู‡ุง.

ุงู„ุฅุตุฏุงุฑุงุช ุงู„ู‚ุฏูŠู…ุฉ ู…ู† C ++


ูƒู„ ู…ุง ุณุจู‚ ูŠุนู…ู„ ู…ุน ุงู„ุฅุตุฏุงุฑ C ++ 11 ุŒ ูˆุงู„ูุฑู‚ ุงู„ูˆุญูŠุฏ ู‡ูˆ ู„ูุธ ุชุนุฑูŠูุงุช ุงู„ู‚ูŠูˆุฏ ุจูŠู† ุงู„ุฅุตุฏุงุฑุงุช ุงู„ู‚ูŠุงุณูŠุฉ:

 //C++11 template< typename T > using IsSigned = typename std::enable_if< std::is_signed< T >::value, bool >::type; //C++14 - std::enable_if_t template< typename T > using IsSigned = std::enable_if_t< std::is_signed< T >::value, bool >; //C++17 - std::is_signed_v template< typename T > using IsSigned = std::enable_if_t< std::is_signed_v< T >, bool >; 

ูˆู„ูƒู† ุงู„ู‚ุงู„ุจ ู„ุง ูŠุฒุงู„ ู‡ูˆ ู†ูุณู‡:

 template< typename T, IsSigned< T > = true > 

ููŠ C ++ 98 ุงู„ู‚ุฏูŠู… ุงู„ุฌูŠุฏ ุŒ ู„ุง ุชูˆุฌุฏ ุฃุณู…ุงุก ู…ุณุชุนุงุฑุฉ ู„ู„ู‚ุงู„ุจ ุŒ ุจุงู„ุฅุถุงูุฉ ุฅู„ู‰ ุฐู„ูƒ ุŒ ู„ุง ูŠู…ูƒู† ุฃู† ุชุญุชูˆูŠ ู‚ูˆุงู„ุจ ุงู„ูˆุธุงุฆู ุนู„ู‰ ุฃู†ูˆุงุน ุฃูˆ ู‚ูŠู… ุงูุชุฑุงุถูŠุฉ. ูŠู…ูƒู†ู†ุง ุฅุฏุฑุงุฌ ูƒูˆุฏ SFINAE ุงู„ุฎุงุต ุจู†ุง ููŠ ู†ูˆุน ุงู„ู†ุชูŠุฌุฉ ุฃูˆ ูู‚ุท ููŠ ู‚ุงุฆู…ุฉ ู…ุนู„ู…ุงุช ุงู„ูˆุธูŠูุฉ. ูŠูˆุตู‰ ุจุงู„ุฎูŠุงุฑ ุงู„ุซุงู†ูŠ ู„ุฃู† ุงู„ู…ู†ุดุฆุงุช ู„ุง ุชุญุชูˆูŠ ุนู„ู‰ ุฃู†ูˆุงุน ุงู„ู†ุชุงุฆุฌ. ุฃูุถู„ ู…ุง ูŠู…ูƒู†ู†ุง ูุนู„ู‡ ู‡ูˆ ุดูŠุก ู…ุซู„ ู‡ุฐุง:

 template< typename T > T myAbs( T val, typename my_enable_if< my_is_signed< T >::value, bool >::type = true ) { return( ( val <= -1 ) ? -val : val ); } 

ูู‚ุท ู„ู„ู…ู‚ุงุฑู†ุฉ - ุงู„ู†ุณุฎุฉ ุงู„ุญุฏูŠุซุฉ ู…ู† C ++:

 template< typename T, IsSigned< T > = true > T myAbs( T val ) { return( ( val <= -1 ) ? -val : val ); } 

ุฅุตุฏุงุฑ C ++ 98 ู‚ุจูŠุญ ุŒ ูŠู‚ุฏู… ู…ุนู„ู…ุฉ ู„ุง ู…ุนู†ู‰ ู„ู‡ุง ุŒ ู„ูƒู†ู‡ ูŠุนู…ู„ - ูŠู…ูƒู†ูƒ ุงุณุชุฎุฏุงู…ู‡ุง ุฅุฐุง ูƒุงู†ุช ุถุฑูˆุฑูŠุฉ ู„ู„ุบุงูŠุฉ. ูˆู†ุนู…: ูŠุฌุจ ุชุทุจูŠู‚ my_enable_if ูˆ my_is_signed ( std :: enable_if std :: is_signed ูƒุงู†ุช ุฌุฏูŠุฏุฉ ููŠ std :: enable_if std :: is_signed C ++ 11).

ุงู„ุญุงู„ุฉ ุงู„ุญุงู„ูŠุฉ


C ++ 17 ุงู„ู…ู‚ุฏู…ุฉ if constexpr ุŒ ุทุฑูŠู‚ุฉ if constexpr ู…ู† ุงู„ุชุนู„ูŠู…ุงุช ุงู„ุจุฑู…ุฌูŠุฉ ุงุณุชู†ุงุฏู‹ุง ุฅู„ู‰ ุงู„ุธุฑูˆู ููŠ ูˆู‚ุช ุงู„ุชุฑุฌู…ุฉ. ูŠุฌุจ ุฃู† ุชูƒูˆู† ุนุจุงุฑุงุช if ูˆุฎู„ุงูู‡ุง ุตุญูŠุญุฉ ุจู†ุงุกู‹ ุŒ ู„ูƒู† ุณูŠุชู… ุชู‚ูŠูŠู… ุงู„ุดุฑุท ููŠ ูˆู‚ุช ุงู„ุชุฑุฌู…ุฉ.

 template< typename T > T myAbs( T val ) { if constexpr( std::is_signed_v< T > ) { return( ( val <= -1 ) ? -val : val ); } else { if constexpr( std::is_unsigned_v< T > ) { return val; } /*else { static_assert( false, "T must be signed or unsigned arithmetic type." ); }*/ } } 

ูƒู…ุง ู†ุฑู‰ ุŒ ุฃุตุจุญุช ูˆุธูŠูุฉ ุงู„ู‚ูŠู…ุฉ ุงู„ู…ุทู„ู‚ุฉ ู„ุฏูŠู†ุง ุฃูƒุซุฑ ุฅุญูƒุงู…ุง ูˆุณู‡ูˆู„ุฉ ููŠ ุงู„ู‚ุฑุงุกุฉ. ูˆู…ุน ุฐู„ูƒ ุŒ ูุฅู† ุงู„ุชุนุงู…ู„ ู…ุน ุงู„ุฃู†ูˆุงุน ุบูŠุฑ ุงู„ู…ุทุงุจู‚ุฉ ู„ูŠุณ ุณู‡ู„ุงู‹. ุฅู† static_assert ุบูŠุฑ ุงู„ู…ุดุฑูˆุท ูŠุฌุนู„ ู‡ุฐุง ุงู„ุจูŠุงู† ุซุงุจุชู‹ุง ุฅู„ู‰ ุญุฏ ู…ุง ุŒ ูˆู‡ูˆ ุฃู…ุฑ ู…ุญุธูˆุฑ ุจู…ูˆุฌุจ ุงู„ู…ุนูŠุงุฑ ุŒ ุจุตุฑู ุงู„ู†ุธุฑ ุนู…ุง ุฅุฐุง ูƒุงู† ูŠุชู… ุชุฌุงู‡ู„ู‡ ุฃู… ู„ุง.

ู„ุญุณู† ุงู„ุญุธ ุŒ ู‡ู†ุงูƒ ุซุบุฑุฉ: ููŠ ูƒุงุฆู†ุงุช ุงู„ู‚ูˆุงู„ุจ ุŒ ู„ุง ูŠุชู… ุฅู†ุดุงุก ุนูˆุงู…ู„ ุงู„ุชุดุบูŠู„ ุงู„ู…ุณู‚ุทุฉ ุฅุฐุง ูƒุงู†ุช ุงู„ุญุงู„ุฉ ู…ุณุชู‚ู„ุฉ ุนู† ุงู„ู‚ูŠู…ุฉ. ! ู…ู…ุชุงุฒ

ูˆุจุงู„ุชุงู„ูŠ ูุฅู† ุงู„ู…ุดูƒู„ุฉ ุงู„ูˆุญูŠุฏุฉ ููŠ ุงู„ูƒูˆุฏ ู‡ูŠ ุฃู†ู‡ุง ุชุชุนุทู„ ุฃุซู†ุงุก ุชุนุฑูŠู ุงู„ู‚ุงู„ุจ. ุฅุฐุง ุงุณุชุทุนู†ุง ุฅุฑุฌุงุก ุชู‚ูŠูŠู… static_assert ุญุชู‰ ูˆู‚ุช ุฅู†ุดุงุก ุงู„ู‚ุงู„ุจ ุŒ ูุณูŠุชู… ุญู„ ุงู„ู…ุดูƒู„ุฉ: ุณูŠุชู… ุฅู†ุดุงุคู‡ ุฅุฐุง ูƒุงู†ุช ุฌู…ูŠุน ุดุฑูˆุทู†ุง ุฎุงุทุฆุฉ ูˆูู‚ุท. ูˆู„ูƒู† ูƒูŠู ูŠู…ูƒู†ู†ุง ุชุฃุฌูŠู„ static_assert ุญุชู‰ ูŠุชู… ุฅู†ุดุงุก ุงู„ู‚ุงู„ุจุŸ ุฌุนู„ ุญุงู„ุชู‡ุง ุชุนุชู…ุฏ ุนู„ู‰ ู†ูˆุน!

 template< typename > inline constexpr bool dependent_false_v{ false }; template< typename T > T myAbs( T val ) { if constexpr( std::is_signed_v< T > ) { return( ( val <= -1 ) ? -val : val ); } else { if constexpr( std::is_unsigned_v< T > ) { return val; } else { static_assert( dependent_false_v< T >, "Unsupported type" ); } } } 

ุนู† ุงู„ู…ุณุชู‚ุจู„


ู†ุญู† ุจุงู„ูุนู„ ู‚ุฑูŠุจูˆู† ุจุงู„ูุนู„ ุŒ ู„ูƒู†ู†ุง ุจุญุงุฌุฉ ุฅู„ู‰ ุงู„ุงู†ุชุธุงุฑ ุจุนุถ ุงู„ูˆู‚ุช ุญุชู‰ ูŠุฃุชูŠ C ++ 20 ุจุงู„ุญู„ ุงู„ู†ู‡ุงุฆูŠ: ุงู„ู…ูุงู‡ูŠู…! ุณูŠุคุฏูŠ ู‡ุฐุง ุฅู„ู‰ ุชุบูŠูŠุฑ ุทุฑูŠู‚ุฉ ุงุณุชุฎุฏุงู… ุงู„ู‚ูˆุงู„ุจ (ูˆ SFINAE) ุชู…ุงู…ู‹ุง.

ุจุงุฎุชุตุงุฑ: ูŠู…ูƒู† ุงุณุชุฎุฏุงู… ุงู„ู…ูุงู‡ูŠู… ู„ู„ุญุฏ ู…ู† ู…ุฌู…ูˆุนุฉ ุงู„ูˆุณุงุฆุท ุงู„ุชูŠ ูŠุชู… ู‚ุจูˆู„ู‡ุง ู„ู…ุนู„ู…ุงุช ุงู„ู‚ุงู„ุจ. ุจุงู„ู†ุณุจุฉ ู„ูˆุธูŠูุฉ ุงู„ู‚ูŠู…ุฉ ุงู„ู…ุทู„ู‚ุฉ ู„ุฏูŠู†ุง ุŒ ูŠู…ูƒู†ู†ุง ุงุณุชุฎุฏุงู… ุงู„ู…ูู‡ูˆู… ุงู„ุชุงู„ูŠ:

 template< typename T > concept bool Arithmetic() { return std::is_arithmetic_v< T >; } 

ูˆูƒูŠู ูŠู…ูƒู†ู†ุง ุงุณุชุฎุฏุงู… ุงู„ู…ูุงู‡ูŠู…ุŸ ู‡ู†ุงูƒ ุซู„ุงุซ ุทุฑู‚:

 //   template< typename T > requires Arithmetic< T >() T myAbs( T val ); //   template< Arithmetic T > T myAbs( T val ); //  Arithmetic myAbs( Arithmetic val ); 

ู„ุงุญุธ ุฃู† ุงู„ู†ู…ูˆุฐุฌ ุงู„ุซุงู„ุซ ู„ุง ูŠุฒุงู„ ูŠุนู„ู† ุนู† ูˆุธูŠูุฉ ุงู„ู‚ุงู„ุจ! ููŠู…ุง ูŠู„ูŠ ุงู„ุชู†ููŠุฐ ุงู„ูƒุงู…ู„ ู„ู€ myAbs ููŠ ุงู„ุฅุตุฏุงุฑ C ++ 20:

 template< typename T > concept bool Arithmetic() { return std::is_arithmetic_v< T >; } Arithmetic myAbs( Arithmetic val ) { if constexpr( std::is_signed_v< decltype( val ) > ) { return( ( val <= -1 ) ? -val : val ); } else { return val; } } int main() { unsigned int a{ myAbs( 5u ) }; int b{ myAbs< int >( 5u ) }; //std::string c{ myAbs( "d" ) }; } 

ู…ูƒุงู„ู…ุฉ ุชู… ุงู„ุชุนู„ูŠู‚ ุนู„ูŠู‡ุง ุชุนุทูŠ ุงู„ุฎุทุฃ ุงู„ุชุงู„ูŠ:

 error: cannot call function 'auto myAbs(auto:1) [with auto:1 = const char*]' constraints not satisfied within 'template<class T> concept bool Arithmetic() [with T = const char*]' concept bool Arithmetic(){ ^~~~~~~~~~ 'std::is_arithmetic_v' evaluated to false 

ุฃุญุซ ุงู„ุฌู…ูŠุน ุนู„ู‰ ุงุณุชุฎุฏุงู… ู‡ุฐู‡ ุงู„ุฃุณุงู„ูŠุจ ุจุฌุฑุฃุฉ ููŠ ุดูุฑุฉ ุงู„ุฅู†ุชุงุฌ ุ› ูˆู‚ุช ุงู„ุชุฌู…ูŠุน ุฃุฑุฎุต ู…ู† ูˆู‚ุช ุงู„ุชุดุบูŠู„. SFINAEing ุณุนูŠุฏ!

Source: https://habr.com/ru/post/ar466915/


All Articles