ぬの部屋(仮)
nu-no-he-ya
  •      12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
         12
    3456789
    10111213141516
    17181920212223
    2425262728  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
       1234
    567891011
    12131415161718
    19202122232425
    26272829   
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28      
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
    1234567
    891011121314
    15161718192021
    22232425262728
           
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
         12
    3456789
    10111213141516
    17181920212223
    242526272829 
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
        123
    45678910
    11121314151617
    18192021222324
    25262728   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    15161718192021
    293031    
           
         12
    3456789
    10111213141516
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
          1
    2345678
    9101112131415
    16171819202122
    232425262728 
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
  • Blender 2.8 python textを追加

    import bpy
    
    

    # textオブジェクトの追加

    fontCurve1
    = bpy.data.curves.new(type="FONT",name="fontCurve1") obj = bpy.data.objects.new("textObject",fontCurve1) obj.data.body = "Hello"# textオブジェクトの内容 # 新しいCollrectionを作成 newCol = bpy.data.collections.new('Collection 1') # 現在のシーンにコレクションをリンク bpy.context.scene.collection.children.link(newCol) newCol.objects.link(obj)

    # フォントの変更

    fnt = bpy.data.fonts.load('C:\Windows\Fonts\HARNGTON.TTF') obj.data.font = fnt
     

    実行結果

    色々な型に対応できる関数を作る(5)double型以外に対応する

    すっかり忘れていたが今までのパターンではdouble型にしか対応していなかった。

    #pragma once
    
    //////////////////////////////////////////////////////
    //////////////////////////////////////////////////////
    // プライマリテンプレート
    template<typename T>
    struct GETTER;
    
    //////////////////////////////////////////////////////
    //////////////////////////////////////////////////////
    // 特殊化用の構造体
    
    //小文字 x,y,z用特殊化用の構造体
    template<typename T>
    struct access_xyz {
      using scalar_t = decltype(T::x);
      static inline scalar_t& X(T& v) { return v.x; }
      static inline scalar_t& Y(T& v) { return v.y; }
      static inline scalar_t& Z(T& v) { return v.z; }
      static inline const scalar_t& X(const T& v) { return v.x; }
      static inline const scalar_t& Y(const T& v) { return v.y; }
      static inline const scalar_t& Z(const T& v) { return v.z; }
    };
    
    //大文字 X,Y,Z用特殊化用の構造体
    template<typename T>
    struct access_XYZ {
      using scalar_t = decltype(T::X);
      static inline scalar_t& X(T& v) { return v.X; }
      static inline scalar_t& Y(T& v) { return v.Y; }
      static inline scalar_t& Z(T& v) { return v.Z; }
      static inline const scalar_t& X(const T& v) { return v.X; }
      static inline const scalar_t& Y(const T& v) { return v.Y; }
      static inline const scalar_t& Z(const T& v) { return v.Z; }
    };
    
    //配列用特殊化用の構造体
    template<typename U,typename T>
    struct access_ARRAY{
      static inline U& X(T& v) { return v[0]; }
      static inline U& Y(T& v) { return v[1]; }
      static inline U& Z(T& v) { return v[2]; }
      static inline const U& X(const T& v) { return v[0]; }
      static inline const U& Y(const T& v) { return v[1]; }
      static inline const U& Z(const T& v) { return v[2]; }
    };
    
    //////////////////////////////////////////////////////
    //////////////////////////////////////////////////////
    // データ型(サンプル)
    // 型1
    struct vec_t {
      double x, y, z;
    };
    
    // 型2
    struct VEC_t {
      double X, Y, Z;
    };
    
    //////////////////////////////////////////////////////
    //////////////////////////////////////////////////////
    //特殊化1(デフォルトの型)
    
    template<>
    struct GETTER<vec_t> :public access_xyz<vec_t> {};
    
    template<>
    struct GETTER<VEC_t> :public access_XYZ<VEC_t> {};
    
    //////////////////////////////////////////////////////
    //////////////////////////////////////////////////////
    // 特殊化2(ポインタ版)
    
    template<typename T>
    struct GETTER<T*> : public access_ARRAY<T,T*> {};
    
    template<class T, std::size_t N>
    struct GETTER<T[N]> : public access_ARRAY<T, T[N]> {};
    
    template<typename T, std::size_t N>
    struct GETTER<std::array<T, N> > : public access_ARRAY<T, std::array<T, N> > {};
    
    //////////////////////////////////////////////////////
    //////////////////////////////////////////////////////
    // 関数本体
    
    template<
      typename T,
      class G = GETTER<T>
    >
    double length(const T & v) {
    
      return
        sqrt(
          G::X(v) * G::X(v) +
          G::Y(v) * G::Y(v) +
          G::Z(v) * G::Z(v)
        );
    }
    
    template<
      typename T,
      class G = GETTER<T>
    >
    void normalize(T & v) {
    
      double L = length(v);
    
      G::X(v) = G::X(v) / L;
      G::Y(v) = G::Y(v) / L;
      G::Z(v) = G::Z(v) / L;
    
    }
    

    色々な型に対応できる関数を作る(4)特殊化を短くする(配列込み)

    前回、配列版の事を忘れていたので追加。

    len.hpp

    #pragma once
    
    //////////////////////////////////////////////////////
    //////////////////////////////////////////////////////
    // プライマリテンプレート
    template<typename T>
    struct GETTER;
    
    //////////////////////////////////////////////////////
    //////////////////////////////////////////////////////
    // 特殊化用の構造体
    
    
    //小文字 x,y,z用特殊化用の構造体 template<typename T> struct access_xyz { static inline double& X(T& v) { return v.x; } static inline double& Y(T& v) { return v.y; } static inline double& Z(T& v) { return v.z; } static inline const double& X(const T& v) { return v.x; } static inline const double& Y(const T& v) { return v.y; } static inline const double& Z(const T& v) { return v.z; } }; //大文字 X,Y,Z用特殊化用の構造体 template<typename T> struct access_XYZ { static inline double& X(T& v) { return v.X; } static inline double& Y(T& v) { return v.Y; } static inline double& Z(T& v) { return v.Z; } static inline const double& X(const T& v) { return v.X; } static inline const double& Y(const T& v) { return v.Y; } static inline const double& Z(const T& v) { return v.Z; } }; //配列用特殊化用の構造体 template<typename T> struct access_ARRAY{ static inline double& X(T& v) { return v[0]; } static inline double& Y(T& v) { return v[1]; } static inline double& Z(T& v) { return v[2]; } static inline const double& X(const T& v) { return v[0]; } static inline const double& Y(const T& v) { return v[1]; } static inline const double& Z(const T& v) { return v[2]; } };
    ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // データ型(サンプル)
    // 型1
    struct vec_t { double x, y, z; }; // 型2 struct VEC_t { double X, Y, Z; };
     
    ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// //特殊化1(デフォルトの型) template<> struct GETTER<vec_t> :public access_xyz<vec_t> {}; template<> struct GETTER<VEC_t> :public access_XYZ<VEC_t> {}; ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // 特殊化2(ポインタ版) template<typename T> struct GETTER<T*> : public access_ARRAY<T*> {}; template<class T, std::size_t N> struct GETTER<T[N]> : public access_ARRAY<T[N]> {}; template<typename T, std::size_t N> struct GETTER<std::array<T, N> > : public access_ARRAY< std::array<T, N> > {};
    ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // 関数本体 template< typename T, class G = GETTER<T> > double length(const T & v) { return sqrt( G::X(v) * G::X(v) + G::Y(v) * G::Y(v) + G::Z(v) * G::Z(v) ); } template< typename T, class G = GETTER<T> > void normalize(T & v) { double L = length(v); G::X(v) = G::X(v) / L; G::Y(v) = G::Y(v) / L; G::Z(v) = G::Z(v) / L; }

    main.cpp

    #include <iostream>
    #include <array>
    
    #include "len.hpp"
    
    
    ////エントリポイント
    int main()
    {
      double L;
      vec_t vv={ 1,1,1 };
      L = length(vv);
      std::cout << L << std::endl;
    
      double xyz[3] = { 1,1,1 };
      L = length(xyz);
      std::cout << L << std::endl;
    
      double* ptr = new double[3]{ 1,1,1 };
      L = length(ptr);
      std::cout << L << std::endl;
    
      std::array<double, 3> ary = { 1,1,1 };
      L = length(ary);
      std::cout << L << std::endl;
    
      int i;
      std::cin >> i;
    
    }
    

    色々な型に対応できる関数を作る(3)特殊化を短くする

    続き

    せっかくテンプレートを使用しているのに、GETTERの特殊化が長すぎる問題がある。

    今回はlength関数しか使用していないので特にそう感じる。x,y,zの要素をとる関数が、例えばinnner,outer,distance...等沢山あれば気にならない。

    とはいえ、短いほうがいいのは間違いないので、できる限り少ない行数で特殊化できないか考える。

    あらかじめ、要素がx,y,zの時に使えるaccess_xyzと、X,Y,Zの時に使えるaccess_XYZを用意しておく。

    #pragma once
    
    
    //////////////////////////////////////////////////////
    //////////////////////////////////////////////////////
    // プライマリテンプレート
    template<typename T>
    struct GETTER;
    
    ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // テンプレート
    template<typename T> struct access_xyz { using arg_t = T; using carg_t = const T; static inline double& X(arg_t& v) { return v.x; } static inline double& Y(arg_t& v) { return v.y; } static inline double& Z(arg_t& v) { return v.z; } static inline const double& X(carg_t& v) { return v.x; } static inline const double& Y(carg_t& v) { return v.y; } static inline const double& Z(carg_t& v) { return v.z; } };

    template<typename T> struct access_XYZ { using arg_t = T; using carg_t = const T; static inline double& X(arg_t& v) { return v.X; } static inline double& Y(arg_t& v) { return v.Y; } static inline double& Z(arg_t& v) { return v.Z; } static inline const double& X(carg_t& v) { return v.X; } static inline const double& Y(carg_t& v) { return v.Y; } static inline const double& Z(carg_t& v) { return v.Z; } };

    ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // ポインタ版 (変更なし) template<typename T> struct GETTER<T*> { using arg_t = T *; using carg_t = const T*; static inline double& X(arg_t v) { return v[0]; } static inline double& Y(arg_t v) { return v[1]; } static inline double& Z(arg_t v) { return v[2]; } static inline const double& X(carg_t v) { return v[0]; } static inline const double& Y(carg_t v) { return v[1]; } static inline const double& Z(carg_t v) { return v[2]; } }; template<class T, std::size_t N> struct GETTER<T[N]> { using arg_t = T[N]; using carg_t = const T[N]; static inline double& X(arg_t v) { return v[0]; } static inline double& Y(arg_t v) { return v[1]; } static inline double& Z(arg_t v) { return v[2]; } static inline const double& X(carg_t v) { return v[0]; } static inline const double& Y(carg_t v) { return v[1]; } static inline const double& Z(carg_t v) { return v[2]; } }; template<typename T, std::size_t N> struct GETTER<std::array<T, N> > { using arg_t = std::array<T, N> &; using carg_t = const std::array<T, N> &; static inline double& X(arg_t v) { return v[0]; } static inline double& Y(arg_t v) { return v[1]; } static inline double& Z(arg_t v) { return v[2]; } static inline const double& X(carg_t v) { return v[0]; } static inline const double& Y(carg_t v) { return v[1]; } static inline const double& Z(carg_t v) { return v[2]; } }; ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // 関数本体 template< typename T, class G = GETTER<T> > double length(const T & v) { return sqrt( G::X(v) * G::X(v) + G::Y(v) * G::Y(v) + G::Z(v) * G::Z(v) ); }

    使用例

    使用したい構造体に合わせて、継承元を変える。

    #include <array>
    
    #include "len.hpp"
    
    //////////////////////////////////////////////////////
    // 型1
    struct vec_t {
      double x, y, z;
    };
    
    //////////////////////////////////////////////////////
    // 型2
    struct VEC_t {
      double X, Y, Z;
    };
    
    
    //特殊化1
    template<>
    struct GETTER<vec_t> :public access_xyz<vec_t> {};
    
    //特殊化2 template<> struct GETTER<VEC_t> :public access_XYZ<VEC_t> {}; //エントリポイント int main() { double L; vec_t vv; vv.x = 1; vv.y = 1; vv.z = 1; L = length(vv); std::cout << L << std::endl; VEC_t VV; VV.X = 1; VV.Y = 1; VV.Z = 1; L = length(VV); std::cout << L << std::endl; int i; std::cin >> i; }

    色々な型に対応できる関数を作る(2)配列/ポインタ版

    前回の続き

    構造体が渡されたときとは別に、ポインタや配列が渡されたときも特殊化する必要がある。

    配列用の特殊化

    プライマリテンプレートが以下の時、

    //プライマリテンプレート
    template<typename T>
    struct GETTER;
    

    ポインタ、配列、std::arrayで別の特殊化が必要

    ポインタ版

    相手がポインタの場合、それを配列とみなすとする。


    特殊化は以下のようになる。

    template<typename T>
    struct GETTER<T*> {
      // ... 
    };
    

    配列版


    相手が配列の場合、ポインタとは別の特殊化が必要になる

    template<class T, std::size_t N>
    struct GETTER<T[N]> {
      // ...
    };
    

    std::array版


    相手がstd::arrayの場合の特殊化は以下

    template<typename T, std::size_t N>
    struct GETTER<std::array<T, N> > {
      // ...
    };
    

    実装例

    #include <type_traits>
    
    #include <array>
    
    #include "len.hpp"
    
    
    template<typename T> struct GETTER<T*> { using arg_t = T*; using carg_t = const T*; static inline double& X(arg_t v) { return v[0]; } static inline double& Y(arg_t v) { return v[1]; } static inline double& Z(arg_t v) { return v[2]; } static inline const double& X(carg_t v) { return v[0]; } static inline const double& Y(carg_t v) { return v[1]; } static inline const double& Z(carg_t v) { return v[2]; } };

    template<class T, std::size_t N> struct GETTER<T[N]> { using arg_t = T[N]; using carg_t = const T[N]; static inline double& X(arg_t v) { return v[0]; } static inline double& Y(arg_t v) { return v[1]; } static inline double& Z(arg_t v) { return v[2]; } static inline const double& X(carg_t v) { return v[0]; } static inline const double& Y(carg_t v) { return v[1]; } static inline const double& Z(carg_t v) { return v[2]; } };
     
    template<typename T, std::size_t N> struct GETTER<std::array<T, N> > { using arg_t = std::array<T, N> &; using carg_t = const std::array<T, N> &; static inline double& X(arg_t v) { return v[0]; } static inline double& Y(arg_t v) { return v[1]; } static inline double& Z(arg_t v) { return v[2]; } static inline const double& X(carg_t v) { return v[0]; } static inline const double& Y(carg_t v) { return v[1]; } static inline const double& Z(carg_t v) { return v[2]; } };

    //エントリポイント int main() { double L; vec_t vv; vv.x = 1; vv.y = 1; vv.z = 1; L = length(vv); std::cout << L << std::endl;
    //配列 double xyz[3]; xyz[0] = 1; xyz[1] = 1; xyz[2] = 1; L = length(xyz); std::cout << L << std::endl;

    //ポインタ double *pxyz = new double[3]; pxyz[0] = 1; pxyz[1] = 1; pxyz[2] = 1; L = length(pxyz); std::cout << L << std::endl;

    //std::array std::array<double, 3> ary; ary[0] = 1; ary[1] = 1; ary[2] = 1; L = length(ary); std::cout << L << std::endl;

    int i; std::cin >> i; }

    色々な型に対応できる関数を作る(1)構造体対応

    1.基本

    以下のようなコードがある。vec_tは三次元のベクトル型で、lengthはその長さを計算する

    len.hpp

    #pragma once
    
    
    struct vec_t { double x, y, z; };
    double length(const vec_t& v) { return sqrt( v.x * v.x + v.y * v.y + v.z * v.z ); }

    source.cpp

    #include <iostream>
    
    #include "len.hpp"
    
    int main()
    {
      vec_t vv;
      vv.x = 1;
      vv.y = 1;
      vv.z = 1;
    
      double dbl = length(vv);
    
      std::cout << dbl << std::endl;
    
      int i;
      std::cin >>i;
    
    }
    

    lengthはシンプルで可読性が高いが、移植性には欠ける。

    具体的にはvec_tにしか対応していない。(故に読みやすいのだが。)

    2.テンプレート化

    length関数をテンプレート化する

    len.hpp

    #pragma once
    
    
    struct vec_t { double x, y, z; };
    template<typename T> double length(const T& v) { return sqrt( v.x * v.x + v.y * v.y + v.z * v.z ); }

    source.cpp

    これでx,y,zというメンバ変数がpublicにあればコンパイルできる。

    #include <iostream>
    
    #include "len.hpp"
    
    
    struct xyz_t { double x, y, z; };
    int main() { double L; vec_t vv; vv.x = 1; vv.y = 1; vv.z = 1; L = length(vv); std::cout << L << std::endl; xyz_t xyz; xyz.x = 1; xyz.y = 1; xyz.z = 1; L = length(xyz); std::cout << L << std::endl; int i; std::cin >>i; }

    ではx,y,zがないときはどうすればいいのか。

    3.テンプレートでデータ取得用の関数を指定する

    len.hpp

    #pragma once
    
    
    //デフォルトの型 struct vec_t { double x, y, z; };
    //プライマリテンプレート template<typename T> struct GETTER;
    //特殊化1(デフォルトの型) template<> struct GETTER<vec_t> { using arg_t = vec_t; using carg_t = const vec_t; static inline double& X(arg_t& v) { return v.x; } static inline double& Y(arg_t& v) { return v.y; } static inline double& Z(arg_t& v) { return v.z; } static inline const double& X(carg_t& v) { return v.x; } static inline const double& Y(carg_t& v) { return v.y; } static inline const double& Z(carg_t& v) { return v.z; } };

    template< typename T, class G = GETTER<T> > double length(const T & v) { return sqrt( G::X(v) * G::X(v) + G::Y(v) * G::Y(v) + G::Z(v) * G::Z(v) ); }

    source.hpp

    #include <iostream>
    
    #include "len.hpp"
    
    //自作の型
    struct XYZ_t {
      double X, Y, Z;
    };
     
    //特殊化2(自作の型用) template<> struct GETTER<XYZ_t> { using arg_t = XYZ_t; using carg_t = const XYZ_t; static inline double& X(arg_t& v) { return v.X; } static inline double& Y(arg_t& v) { return v.Y; } static inline double& Z(arg_t& v) { return v.Z; } static inline const double& X(carg_t& v) { return v.X; } static inline const double& Y(carg_t& v) { return v.Y; } static inline const double& Z(carg_t& v) { return v.Z; } };
    //エントリポイント int main() { double L; vec_t vv; vv.x = 1; vv.y = 1; vv.z = 1; L = length(vv); std::cout << L << std::endl; XYZ_t xyz; xyz.X = 1; xyz.X = 1; xyz.X = 1; L = length(xyz); std::cout << L << std::endl; int i; std::cin >> i; }

    これでGETTERを定義すればどんな型でも使える。

    続く...

    C++の64bit版のhash_combine

    Boostのhash_combineの64bit版

    https://github.com/HowardHinnant/hash_append/issues/7

    最新のC++にはBoostから正式に仕様に含められたhashが「unordered_map」という名前で入っているが、hash_combineは取り入れられていないらしい。なので自分で作る必要がある。

    この時、多くはBoostを参考にすると思うのだが、Boostの中のマジックナンバーがどうやら32bitのもので、64bit版の場合、この数字はどうなるんだ?というのが上記サイトの議論の内容となっている。

    そもそもこの数字はTEAアルゴリズムというものが根拠らしく、64bitの場合と、さらに128bitの場合の値が上げられている。

    ビット数16進数表記の値
    80x9e
    160x9e37
    320x9e3779b9
    640x9e3779b97f4a7c15
    1280x9e3779b97f4a7c15f39cc0605d396154

    そして64bitは32bitの二倍なので、シフト量も二倍にする。

    seed ^= std::hash<T>{}(val) + 0x9e3779b9U + (seed<<6) + (seed>>2);

    seed ^= std::hash<T>{}(val) + 0x9e3779b97f4a7c15LLU + (seed<<12) + (seed>>4);

    なおこの(Boostの)HashCombineはさして優れているわけでは無いと言うことで、別の方法があるならそれを使うべきと言うような主張をちらほら見かける。

    CityHashからの借用

    https://stackoverflow.com/questions/8513911/how-to-create-a-good-hash-combine-with-64-bit-output-inspired-by-boosthash-co

    CityHashはGoogleが考案したハッシュアルゴリズムで、MITライセンス(らしい)。そこから転用したコードが紹介されている。

    template <class T> inline void hash_combine(std::size_t& seed, const T& v)
    {
        std::hash<T> hasher;
        const std::size_t kMul = 0x9ddfea08eb382d69ULL;
        std::size_t a = (hasher(v) ^ seed) * kMul;
        a ^= (a >> 47);
        std::size_t b = (seed ^ a) * kMul;
        b ^= (b >> 47);
        seed = b * kMul;
    }
    

    (このスニペットは、CityHashコードの「実質的な部分」を構成するものではないため、ここや他の場所に複製しても問題ないと思いますが、CityHashのソースとライセンス契約を確認して、自分で決めてください)

    (Google翻訳)

    CMake中に出てきた大量のC2220への対処

    c2220 警告をエラーとして扱いました。'object' ファイルは生成されません。

    Open3DのCMakeを試していたのだけれど、VC++2017でC2220が大量発生した。関連するプロジェクトが無数にある場合で、一つ一つプロパティを開くのは避けたい場合、王道な方法が見つからなかったのでCMakeList.txtを編集して対処した。

    プロジェクトが少ない場合

    単体のプロジェクトなら、以下のように /WX オプションを解除することで対処できる。

    プロジェクトが複数の場合

    CMakeLists.txtをテキストエディタで開き、中の「/WX」という部分を削除する。

    set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MP ${MSVC_WARNING_IGNORE} /WX")
    set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MP ${MSVC_WARNING_IGNORE} /WX")
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MP ${MSVC_WARNING_IGNORE} /WX")
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MP ${MSVC_WARNING_IGNORE} /WX")

    glewを使用しないでC++からGLSLを使用

    glewのライセンス

    https://github.com/nigels-com/glew#copyright-and-licensing

    GLEW is originally derived from the EXTGL project by Lev Povalahev. The source code is licensed under the Modified BSD License, the Mesa 3-D License (MIT) and the Khronos License (MIT).

    The automatic code generation scripts are released under the GNU GPL.

    glewはBSD LicenseかMITライセンス。普通誰も気にしないが、気に入らない場合は使用できない。

    けれどやっていることはヘッダファイル側で定数を#defineしているのと、dll側でwglGetProcAddressしているだけ(多分)なので、必要な部分だけ自前で書くことも不可能ではない。

    myglinit.hpp

    #pragma once
    
    #include <gl/GL.h>
    
    typedef ptrdiff_t GLsizeiptr;
    typedef char GLchar;
    
    //サンプルのコンパイルに必要なものだけを取り出したもの
    
    
    // 関数ポインタ型
    using PFNGLGENBUFFERSPROC               = void(_stdcall*) (GLsizei n, GLuint* buffers);
    using PFNGLBINDBUFFERPROC               = void(_stdcall*) (GLenum target, GLuint buffer);
    using PFNGLBUFFERDATAPROC               = void(_stdcall*) (GLenum target, GLsizeiptr size, const void* data, GLenum usage);
    using PFNGLCREATESHADERPROC             = GLuint(_stdcall*) (GLenum type);
    using PFNGLSHADERSOURCEPROC             = void(_stdcall*) (GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length);
    using PFNGLCOMPILESHADERPROC            = void(_stdcall*) (GLuint shader);
    using PFNGLGETSHADERIVPROC              = void(_stdcall*) (GLuint shader, GLenum pname, GLint* param);
    using PFNGLGETSHADERINFOLOGPROC         = void(_stdcall*) (GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
    using PFNGLCREATEPROGRAMPROC            = GLuint(_stdcall*) (void);
    using PFNGLATTACHSHADERPROC             = void(_stdcall*) (GLuint program, GLuint shader);
    using PFNGLLINKPROGRAMPROC              = void(_stdcall*) (GLuint program);
    using PFNGLGETPROGRAMIVPROC             = void(_stdcall*) (GLuint program, GLenum pname, GLint* param);
    using PFNGLGETPROGRAMINFOLOGPROC        = void(_stdcall*) (GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
    using PFNGLUSEPROGRAMPROC               = void(_stdcall*) (GLuint program);
    using PFNGLENABLEVERTEXATTRIBARRAYPROC  = void(_stdcall*) (GLuint index);
    using PFNGLVERTEXATTRIBPOINTERPROC      = void(_stdcall*) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);
    using PFNGLDISABLEVERTEXATTRIBARRAYPROC = void(_stdcall*) (GLuint index);
    
    // 定数
    #define GL_ARRAY_BUFFER    0x8892
    #define GL_STATIC_DRAW     0x88E4
    #define GL_VERTEX_SHADER   0x8B31
    #define GL_COMPILE_STATUS  0x8B81
    #define GL_INFO_LOG_LENGTH 0x8B84
    #define GL_FRAGMENT_SHADER 0x8B30
    #define GL_LINK_STATUS     0x8B82
    
    // wglGetProcAddressで取得したアドレスを格納する変数(グローバル)
    PFNGLGENBUFFERSPROC               glGenBuffers;
    PFNGLBINDBUFFERPROC               glBindBuffer;
    PFNGLBUFFERDATAPROC               glBufferData;
    PFNGLCREATESHADERPROC             glCreateShader;
    PFNGLSHADERSOURCEPROC             glShaderSource;
    PFNGLCOMPILESHADERPROC            glCompileShader;
    PFNGLGETSHADERIVPROC              glGetShaderiv;
    PFNGLGETSHADERINFOLOGPROC         glGetShaderInfoLog;
    PFNGLCREATEPROGRAMPROC            glCreateProgram;
    PFNGLATTACHSHADERPROC             glAttachShader;
    PFNGLLINKPROGRAMPROC              glLinkProgram;
    PFNGLGETPROGRAMIVPROC             glGetProgramiv;
    PFNGLGETPROGRAMINFOLOGPROC        glGetProgramInfoLog;
    PFNGLUSEPROGRAMPROC               glUseProgram;
    PFNGLENABLEVERTEXATTRIBARRAYPROC  glEnableVertexAttribArray;
    PFNGLVERTEXATTRIBPOINTERPROC      glVertexAttribPointer;
    PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
    
    
    //関数のアドレスを取得
    inline void myglinit() {
    
      glAttachShader             = (PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader");
      glBindBuffer               = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer");
      glBufferData               = (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData");
      glCompileShader            = (PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader");
      glCreateProgram            = (PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram");
      glCreateShader             = (PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader");
      glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glDisableVertexAttribArray");
      glEnableVertexAttribArray  = (PFNGLENABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glEnableVertexAttribArray");
      glGenBuffers               = (PFNGLGENBUFFERSPROC)wglGetProcAddress("glGenBuffers");
      glGetProgramInfoLog        = (PFNGLGETPROGRAMINFOLOGPROC)wglGetProcAddress("glGetProgramInfoLog");
      glGetProgramiv             = (PFNGLGETPROGRAMIVPROC)wglGetProcAddress("glGetProgramiv");
      glGetShaderInfoLog         = (PFNGLGETSHADERINFOLOGPROC)wglGetProcAddress("glGetShaderInfoLog");
      glGetShaderiv              = (PFNGLGETSHADERIVPROC)wglGetProcAddress("glGetShaderiv");
      glLinkProgram              = (PFNGLLINKPROGRAMPROC)wglGetProcAddress("glLinkProgram");
      glShaderSource             = (PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource");
      glUseProgram               = (PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram");
      glVertexAttribPointer      = (PFNGLVERTEXATTRIBPOINTERPROC)wglGetProcAddress("glVertexAttribPointer");
    
    }
    

    サンプルコード(本体)

    元のソースコード

    #include <iostream>
    
    #pragma warning(disable:4996)
    
    //#pragma comment(lib,"glew32.lib")  --- しない
    
    
    //#include <gl/glew.h>   --- しない
    #include <Windows.h>
    #include <GL/glut.h>
    
    #include <fstream>
    #include <sstream>
    #include <vector>
    #include <algorithm>
    
    #include "myglinit.hpp"
    
    
    void init(void);
    void display(void);
    
    void link_program();
    void prepare_buffers();
    void prepare_vertex_shader();
    void prepare_fragment_shader();
    
    
    
    int main(int argc, char *argv[])
    {
      glutInit(&argc, argv);
      glutInitDisplayMode(GLUT_RGBA);
      glutCreateWindow(argv[0]);
      glutDisplayFunc(display);
      //■ glewInit(); // glewの初期化 --- しない
      myglinit();// glewInit()関数の代わり
      init();
      glutMainLoop();
      return 0;
    }
    
    void init(void)
    {
    
      //頂点データと色情報の作成
      prepare_buffers();
    
      //頂点シェーダの準備
      prepare_vertex_shader();
    
      //フラグメントシェーダの準備
      prepare_fragment_shader();
    
      //プログラムのリンク
      link_program();
    
    }
    
    //バッファとデータ
    typedef GLfloat points_t[3];
    GLuint vertexbuffer;//バッファのIDを格納する変数
    GLuint colorbuffer;//バッファのIDを格納する変数
    points_t position[3];
    points_t color[3];
    
    //////////////////////////////////////////////////
    void prepare_buffers() {
    
      //頂点座標
      position[0][0] = 0;
      position[0][1] = 0.5;
      position[0][2] = 0;
    
      position[1][0] = 0.5;
      position[1][1] = -0.5;
      position[1][2] = 0;
    
      position[2][0] = -0.5;
      position[2][1] = -0.5;
      position[2][2] = 0;
    
    
      //色
      color[0][0] = 1.0;
      color[0][1] = 0.0;
      color[0][2] = 0.0;
    
      color[1][0] = 0.0;
      color[1][1] = 1.0;
      color[1][2] = 0.0;
    
      color[2][0] = 0.0;
      color[2][1] = 0.0;
      color[2][2] = 1.0;
    
      glGenBuffers(1, &vertexbuffer);
      glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
      glBufferData(
        GL_ARRAY_BUFFER,
        3 * 3 * sizeof(GLfloat),
        position,
        GL_STATIC_DRAW);
    
      glGenBuffers(1, &colorbuffer);
      glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
      glBufferData(
        GL_ARRAY_BUFFER,
        3 * 3 * sizeof(GLfloat),
        color,
        GL_STATIC_DRAW);
    
    }
    
    GLuint VertexShaderID;
    
    void prepare_vertex_shader() {
    
      //////////////////////////////////////////////
        // シェーダを作ります
        // (作るといっても宣言みたいなもの)
      VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
    
      ////////////////////////////////////////////
      // ファイルから頂点シェーダを読み込みます。
      // 注意 ここはSTLのifstreamとかstringstreamの使い方の話で、
      // OpenGL命令は一つも無い。
      const char * vertex_file_path = ".\\verts.sh";
      std::string VertexShaderCode;
      std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
      if (VertexShaderStream.is_open())
      {
        std::stringstream sstr;
        sstr << VertexShaderStream.rdbuf();
        VertexShaderCode = sstr.str();
        VertexShaderStream.close();
      }
      ////////////////////////////////////////////
      // 頂点シェーダをコンパイルします。
      printf("Compiling shader : %s\n", vertex_file_path);
      char const * VertexSourcePointer = VertexShaderCode.c_str();
      glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL);
      glCompileShader(VertexShaderID);
    
      ////////////////////////////////////////////
      // エラーチェック
      GLint Result = GL_FALSE;
      int InfoLogLength;
    
      // 頂点シェーダをチェックします。
      glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
      glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
      if (Result == FALSE) {
        std::vector<char> VertexShaderErrorMessage(InfoLogLength);
        glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
        fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]);
      }
    
    }
    
    GLuint FragmentShaderID;
    
    void prepare_fragment_shader() {
    
      /////////////////////////////////////////////
      // シェーダを作ります。
      FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
    
      /////////////////////////////////////////////
      // ファイルからフラグメントシェーダを読み込みます。
      const char * fragment_file_path = ".\\frags.sh";
      std::string FragmentShaderCode;
      std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
      if (FragmentShaderStream.is_open()) {
        std::stringstream sstr;
        sstr << FragmentShaderStream.rdbuf();
        FragmentShaderCode = sstr.str();
        FragmentShaderStream.close();
      }
    
      /////////////////////////////////////////////
      // フラグメントシェーダをコンパイルします。
      printf("Compiling shader : %s\n", fragment_file_path);
      char const * FragmentSourcePointer = FragmentShaderCode.c_str();
      glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer, NULL);
      glCompileShader(FragmentShaderID);
    
      GLint Result = GL_FALSE;
      int InfoLogLength;
    
      /////////////////////////////////////////////
      // フラグメントシェーダをチェックします。
      glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
      glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
      if (Result == GL_FALSE) {
        std::vector<char> FragmentShaderErrorMessage(InfoLogLength);
        glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
        fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]);
      }
    }
    
    GLuint ProgramID;
    
    void link_program() {
    
      GLint Result = GL_FALSE;
      int InfoLogLength;
    
      ////////////////////////////////////////
      // プログラムをリンクします。
      fprintf(stdout, "Linking program\n");
      ProgramID = glCreateProgram();
      glAttachShader(ProgramID, VertexShaderID);
      glAttachShader(ProgramID, FragmentShaderID);
      glLinkProgram(ProgramID);
    
      ////////////////////////////////////////
      // プログラムをチェックします。
      glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
      glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
      std::vector<char> ProgramErrorMessage((std::max)(InfoLogLength, int(1)));
      glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
      fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);
    
    }
    
    void display(void)
    {
      glClearColor(0, 0, 0, 1);
      glClear(GL_COLOR_BUFFER_BIT);
    
      glLoadIdentity();
      glTranslated(0.5, 0.0, 0.0);//平行移動
    
      // シェーダを使う
      glUseProgram(ProgramID);
    
      // 頂点バッファ:頂点
      glEnableVertexAttribArray(0);
      glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
      glVertexAttribPointer(
        0,                  // シェーダ内のlayoutとあわせる
        3,                  // 1要素の要素数(x,y,z)で3要素
        GL_FLOAT,           // タイプ
        GL_FALSE,           // 正規化しない(データが整数型の時)
        0,                  // ストライド
        (void*)0            // 配列バッファオフセット
      );
    
      // カラーバッファを有効にする
      glEnableVertexAttribArray(1);
      glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
      glVertexAttribPointer(
        1,                  // シェーダ内のlayoutとあわせる
        3,                  // 1要素の要素数(r,g,b)で3要素
        GL_FLOAT,           // タイプ
        GL_FALSE,           // 正規化しない(データが整数型の時)
        0,                  // ストライド
        (void*)0            // 配列バッファオフセット
      );
    
      // 三角形を描きます!
      glDrawArrays(GL_TRIANGLES, 0, 3);
    
      glDisableVertexAttribArray(0);//バッファを無効にする
      glDisableVertexAttribArray(1);
    
      glFlush();
    }
    

    後書き

    他にもリンクしちゃいけないときとかもこの方法をとることになると思う。ただその場合はglext.hを使えば自分で#define やtypedefを並べたりしなくて良くなる・・・のか?

    「MIT Licenseを気にする状況ってどんな状況?」とか言う人がいそうなのだけれど、個人でならともかく業務でやっていると、自分より上の層で「俺が理解できないものは低品質なガラクタ」とか「俺の知らないものは使えないゴミ」等の謎理論で意味不明な利用制限がかかったりするので、できるかできないかぐらいは把握しておいた方がいい。後は、そういう契約になってるんだ!とか後から言われたり。しないかな?しないよね。

    C/C++で負数の右論理シフト(>>)をする

    概要

    ・ビットシフト(>>)には算術シフトと論理シフトがある。

    ・算術シフトは負数をシフトすると左側が1で埋まる (Arithmetic shift)

    ・論理シフトは負数をシフトすると左側が0で埋まる (Logical shift)

    ・どちらの挙動をするかは処理系依存

    ということで、強制的に論理シフトしたい時は工夫する必要がある。

    結論

    unsignedにキャストする。以下C++のコード。

    具体例1

    #include <iostream>
    
    //表示のためにbitsetを使う
    #include <bitset>
    
    int main()
    {
      char val = -40;
    
      char S = val;
      char A = val >> 2;//処理系依存 VC++2019では算術シフト
      char L = static_cast<unsigned char>(val) >> 2;//論理シフト
    
      std::bitset<8> Sdisp(S);
      std::bitset<8> Adisp(A);
      std::bitset<8> Ldisp(L);
      std::cout << "source                   : " << Sdisp << " == " << static_cast<int>(S) << '\n';
      std::cout << "not cast         and >>2 : " << Adisp << " == " << static_cast<int>(A) << '\n';
      std::cout << "cast to unsigned and >>2 : " << Ldisp << " == " << static_cast<int>(L) << '\n';
    
      getchar();
    
      return 0;
    }
    

    具体例2(テンプレート)

    同じ事を関数化するなら以下のような感じになる。

    #include <iostream>
    #include<type_traits>
    
    //! @brief 論理右シフト
    //! @param [in] val 右シフトする値
    //! @param [in] shift 右シフトするビット数
    //! @return val >> shift
    template<typename T>
    inline auto logical_right_shift(const T val,const int shift) {
      return
        static_cast<
          typename std::make_unsigned<T>::type>(val) >> shift;
    }
    
    int main()
    {
    
      char val = -40;
    
      char S = val;
      char A = val >> 2;//処理系依存 VC++2019では算術シフト
      char L = logical_right_shift(val, 2);//論理シフト
    
      std::bitset<8> Sdisp(S);
      std::bitset<8> Adisp(A);
      std::bitset<8> Ldisp(L);
      std::cout << "source                    : " << Sdisp << " == " << static_cast<int>(S) << '\n';
      std::cout << "not cast          and >>2 : " << Adisp << " == " << static_cast<int>(A) << '\n';
      std::cout << "logicalrightshift 2       : " << Ldisp << " == " << static_cast<int>(L) << '\n';
    
    
      getchar();
    }
    

    あとがき

    負数の算術シフトが処理系依存とは。流石Cと言わざるを得ない。