茂加部珈琲店

主にtech関連のメモ置き場です

VSCodeでMSYS2+fishを使う

settings.jsonに以下を追加すればよい

    "terminal.integrated.shell.windows": "C:\\Windows\\System32\\cmd.exe",
    "terminal.integrated.shellArgs.windows": [
        "/K","C:\\msys64\\msys2_shell.cmd -mingw64 -defterm -no-start -here -full-path -c fish & exit 0"
    ]

ターミナル起動時にfishを呼んで、fishが終了したときにターミナルも終了させます
なんか時々表示が崩れたり謎の改行が入ったりする

追記:
改行文字(\u23CE)が表示されるのはWindowsのバグなのでしょうかね

github.com

参照: msys2_shell.cmdを使ってVS Codeの総合シェルをMSYS2 bashにする

フレキシブル配列メンバをC++で

こんにちは。c++ネタ。

flexible array member

プログラミングをしていると、大きさのわからない配列を扱いたい時があります。
間接参照を挟まず、構造体に直接配列を埋め込む手法はCなどではよく使われています
こういった配列を扱うため、C99からはフレキシブル配列flexible array memberという機能が追加されました。 使い方は以下のようになります

struct flexArrayStruct {
  int num;
  int data[];
};

末尾のdata[]がフレキシブル配列で、要素数の不明な配列を表します。プログラムは実行時に任意の長さのペイロードを含むオブジェクトをメモリ上に確保してアクセスすることができます。

フレキシブル配列の実体は大雑把に言えば大きさ0の配列です。つまり、事前に「次に来る要素」にアクセスする手段を提供する手段ということです。

C++でフレキシブル配列メンバを模倣する その1

本題に入りますが、C++はC99ベースに作られていないので、フレキシブル配列を使用することはできません。
いくつかのコンパイラは独自拡張としてフレキシブル配列をサポートしています

struct flexArrayStruct {
    int num;
    int data[]; // gcc/clangでコンパイル可能
};

しかし、フレキシブル配列を持つクラスは継承することができません。

  struct Derived : flexArrayStruct {}; // error: base class 'flexArrayStruct' has a flexible array member

これは異論がある人もいると思いますが、フレキシブル配列を持つ構造体を継承すれば、ポインタがキャスト可能になり若干嬉しいです。
そこで、フレキシブル配列ではなく、長さゼロの配列を使用します

// gcc/clangでコンパイル可能
struct flexArrayStruct {
    int num;
    int data[0] = {};
};

struct Derived : flexArrayStruct {
    Derived() :flexArrayStruct{8} {}
    int data[8] = {1,2,3,4,5,6,7,8};
};

flexArrayStruct::dataDerived::dataはメモリ上で同一の場所を表します。
C++の規格上は、長さゼロの配列も、固有のアドレスを持たないオブジェクトも違法です。
そもそも配列の要素数を超えたアクセスはUBですが、耳から天使を召喚して何とかしてください
(ちなみにstd::array<0>は許されていますが、オブジェクトのサイズはゼロではないので注意) また、clang/gccではコンパイルできますが、ゼロ長配列を持つ基底クラスを許さないmsvcではコンパイルできません。

C++でフレキシブル配列メンバを模倣する その2

MSVCでもコンパイルしたい場合は上記の手法は使えませんでした。
こういうときは何も考えずにテンプレートを使ってみるのがC++

template <int N=1>
struct A : A<N-1> {
    int _data_element= {};
};
template <>
struct A<1> {
    int num;
    int data[1] = {};
};
struct D : A<8> {
  D() :A<8>{8,1,2,3,4,5,6,7,8} {}
};

うーん… 非常に危険な香りがしますね

いずれにせよ、C++でフレキシブル配列を行儀よくやるのは無理そうというのが感想です。 より行儀が良い手法としてはポインタ演算でゴリゴリやるしかなさそうです。 フレキシブル配列メンバが規格に入れば良いんですが、忘れられてしまったんでしょうか

[g++7.1] ジェネリックラムダが不要な場合にもインスタンス化されるバグ

ちょっと調べたのでメモ
以下のコードはg++ 7.1、g++7.2でコンパイルに失敗します。

#include <variant>
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

using v = std::variant<double, long, bool>;
 
constexpr const char* get_name(const v& v) {
   return std::visit(
    overloaded{
      [](bool) constexpr { return "bool"; },
      [](double) constexpr { return "double"; },
      [](long) constexpr { return "long"; }, 
      // 網羅していない場合はコンパイルを失敗させる
      [](auto a) constexpr { static_assert(!sizeof(decltype(a)));  }},
    v);
}

これはジェネリックラムダが不要な場合にもインスタンス化されるためです。
以前から報告されており、g++7.3で修正されました。

メンバ関数テンプレートでC2783が出る場合

小ネタなのですが VC++(VS2017 15.5.2)で以下のコードはコンパイルに失敗します。
clangとgccでは通ります。

#include <type_traits>

struct Foo {
  template <class U = int, class = std::enable_if_t<std::is_same_v<U,int>>>
  void f();
};

//template <class U, class> // <- Ok.
template <class, class> // <- C2783: could not deduce template argument for '<unnamed-symbol>'
void Foo::f(){}

int main()
{
  Foo f;
  f.f();
}

エラメッセージでは宣言を確認してくださいなどと書かれていますが、問題はコメントアウトしてあるテンプレートパラメータのようです。
型名までしっかり一致させないといけないので注意。

if constexprを失敗させる

if constexprを与えられた型によって失敗させる場合は、
型に依存したパラメータをstatic_assertに渡してやれば良いみたいです。

saka1_pさんの記事によれば、

template <typename T>
constexpr bool false_v = false;

のような定数を定義して、

  // if constexprの内部で
  static_assert(false_v<T>, "invalid type T");

のようにするらしいです。

個人的には

  static_assert(!sizeof(T), "invalid type T");

が好みです。

VSCodeでcmakeを走らせる

コマンド一つでcmakeやctestを走らせたかったのです。

VSCodeではtask.jsonを使って簡単にできるみたいです.
WindowsではデフォルトのコンパイラVC++なので、MinGWを指定してあります
mingw-64でも動きました。

Ctrl+Shift+B で走ります

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "presentation": {
    "echo": true,
    "reveal": "always",
    "focus": false,
    "panel": "new"
  },
  "tasks": [
    {
      "label": "build",
      "type": "shell",
      "windows": {
        "command": "",
        "args": [
          "mkdir build; cd build; cmake -G 'MinGW Makefiles' ..; cmake --build .; ctest -V -C Debug"
        ]
       },
      "linux": {
        "command": "sh",
        "args": [
          "mkdir build; cd build; cmake ..; cmake --build .; ctest -V"
        ]
       },
       "problemMatcher": []
    }
  ]
}

テンプレートで型情報を作る

C++勉強ネタです

テンプレートを使って、関数型言語の型情報を生成してみます(やっつけなのでバグがあるかも)

値型はValue, λ抽象はArrowになっています。 とりあえずValueには設定された文字列を格納し、Arrowは単にリストを作ってるだけです。

型Tが関数型を持つ場合は、std::tupleシグネチャを格納しておきます

静的変数のアドレスはconstexprとして、初期化前に取得することができます。
依存関係のある静的変数を初期化するのって大変ですよね…
staticローカル変数を使っても良いのですが、そうすると初期化が再帰してUBになるかもです

#include <tuple>
#include <iostream>
#include <variant>
#include <cassert>

template <class T>
struct traits;

// value type
struct Value;
// arrow type
struct Arrow;
// union
using Type = std::variant<Arrow,Value>;

struct Arrow{
  Type* captured;
  Type* returns;
};
struct Value{
  const char* name;
};

template <class T>
struct value_type{
  static Type type;
};

// arrow_type impl
template <class T, class ...Ts>
struct arrow_type_{
  static Type type;
};
// arrow_type impl
template <class T1, class T2>
struct arrow_type_<T1,T2>{
  static Type type;
};

template <class T, class ...Ts>
struct arrow_type;

template <class T, class ...Ts>
struct arrow_type<T, std::tuple<Ts...>>{
  static constexpr Type* type = &arrow_type_<Ts...>::type;
};

template <class T, class = void>
struct object_type {
  static constexpr Type* type = arrow_type<T,typename T::type>::type;
};

template <class T>
struct object_type<T, std::void_t<decltype(traits<T>::name)>>{
  static constexpr Type* type = &value_type<T>::type;
};

template <class T>
Type value_type<T>::type {Value{traits<T>::name}};

template <class T, class ...Ts>
Type arrow_type_<T,Ts...>::type {Arrow{ object_type<T>::type, &arrow_type<Ts...>::type }};

template <class T1, class T2>
Type arrow_type_<T1,T2>::type {Arrow{object_type<T1>::type, object_type<T2>::type}};

// define int type
template <>
struct traits<int>{
  static constexpr const char* name = "int";
};
int main () {    
  struct foo{
    // basic closure type (int->int)
    using type = std::tuple<int,int>;
  };
  struct bar{
    // recursive closure type (bar->int) 
    using type = std::tuple<bar,int>;
  };
  // value
  auto i = object_type<int>::type;
  std::cout << std::get<Value>(*i).name << std::endl; // int
  // closure
  auto f = object_type<foo>::type;
  assert(std::get<Arrow>(*f).captured == i); 
  assert(std::get<Arrow>(*f).returns == i); 
  // recursive
  auto b = object_type<bar>::type;
  assert(b == std::get<Arrow>(*b).captured);
  return 0;
}