Protection against type violations in custom template parameters

I usually use std::size_twhere integral constants are required in the template parameters. However, I noticed that the type system does not protect me from users who are happy to pass negative numbers as arguments to these parameters.

For example, the following compilations giving catastrophic results:

#include <iostream>

template<std::size_t I>
struct E1
{
     static void apply()
     {
         std::cout << I << std::endl;
     }
};

template<typename T>
constexpr T a = T { -1 }; 

template<std::size_t... Is>
void E2()
{
    for (auto&& i : {Is...}) std::cout << i << " "; 
    std::cout << std::endl;
}

int main()
{
    E1<-1>::apply();
    E2<-1, -2, -3>(); 
    //std::cout << a<std::size_t>; 
}

Interestingly, this is not allowed for template variables (uncommenting the last line in maincauses a compilation error).

Is there any solution / workaround for case structand function?

+4
source share
2 answers

GCC, ( ) . , , :

template<        char> void   f () {}
template<unsigned int> void   g () {}


template<unsigned int> struct A {};

int main () {

  f<1024> (); // ill-formed, `char { 1024 }` is a narrowing conversion,
              // see [dcl.init.list]p7

  g<-123> (); // ill-formed, `unsigned int { -123 }` is a narrowing
              // conversion, see [dcl.init.list]p7   

  A<-123>  a; // ill-formed, see previous comment
}

++:

[temp.arg.nontype] p1;

   :

     
  •   
  • -   , (5.19)   -

         

    < snip/" >

      

[expr.const] 3;

T ,    prvalue T,       ,    lvalue-to-rvalue (4.1), (4.5)    (4.7),   (8.5.4).


[: gcc testcase.cpp, clang () . ]

, clang :

error: non-type template argument evaluates to -1, which cannot be narrowed to type 'std::size_t' (aka 'unsigned long') [-Wc++11-narrowing]
E1<-1>::apply();
   ^

error: no matching function for call to 'E2'
E2<-1, -2, -3>(); 
^~~~~~~~~~~~~~

-Wsign-conversion -Werror ( ), ( ). , -Wconversion, -Wsign-conversion ++.

+7

:

test.cpp|24 col 8| error: non-type template argument evaluates to -1, which cannot be narrowed to type 'std::size_t' (aka 'unsigned long') [-Wc++11-narrowing]
 E1<-1>::apply();
    ^
test.cpp|25 col 5| error: no matching function for call to 'E2'
 E2<-1, -2, -3>(); 
 ^~~~~~~~~~~~~~
test.cpp|16 col 6| note: candidate template ignored: invalid explicitly-specified argument for template parameter 'Is'
 void E2()

, ++ 11 .

, , . , , .

+3

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


All Articles