ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

Programming SandboxコミュのSandbox

  • mixiチェック
  • このエントリーをはてなブックマークに追加
見せたいコードを書いたのですが、
当てはまるトピックがなかったので、新しく作らせてもらいます。
ここは、その名のとおり何でもいいところにしたいと思います。

コメント(13)

C/C++でプリプロセッサを駆使してみました。
複数のファイルにまたがってるので気をつけてください。
//////////////////////main.cpp
#include <iostream>

#define MAX 9

#define COUNT MAX

#define SSS(COUNT) int i##COUNT,

int fff(
#include "define.hpp"
#undef SSS
int last
)
{


#define SSS(COUNT) \
std::cout << i##COUNT << std::endl;

#undef COUNT
#define COUNT MAX
#include "define.hpp"
#undef SSS
return 0;
}

int main()
{
#undef COUNT
#define COUNT MAX
#define SSS(COUNT) COUNT,
fff(
#include "define.hpp"
0
);

return 0;
}
////////////////////////define.hpp

#ifdef COUNT

#if COUNT <= 0

#else


#include "count.hpp"
#include "define.hpp"

#endif


#else

#error Don't define Count

#endif
///////////////////////count.hpp

#if COUNT == 10
SSS(10)
#elif COUNT == 9
SSS(9)
#undef COUNT
#define COUNT 8
#elif COUNT == 8
SSS(8)
#undef COUNT
#define COUNT 7
#elif COUNT == 7
SSS(7)
#undef COUNT
#define COUNT 6
#elif COUNT == 6
SSS(6)
#undef COUNT
#define COUNT 5
#elif COUNT == 5
SSS(5)
#undef COUNT
#define COUNT 4
#elif COUNT == 4
SSS(4)
#undef COUNT
#define COUNT 3
#elif COUNT == 3
SSS(3)
#undef COUNT
#define COUNT 2
#elif COUNT == 2
SSS(2)
#undef COUNT
#define COUNT 1
#elif COUNT == 1
SSS(1)
#undef COUNT
#define COUNT 0
#else

#error COUNT over 10
#endif

////////////////////ここまで
これはまた相当トリッキーですね。
関数の引数のところにincludeが入れてしまうとは。
しかもヘッダーはリカーシブinclude
まさに邪道!?
$ cat main.cpp.tmpl
#include <iostream>

/*PLD @list = reverse(1..9) */

int fff(/*PL join(", ", map {"int i$_"} @list) */)
{
        /*PLD foreach my $i (@list) { */
        std::cout << /*PL "i$i" */ << std::endl;
        /*PLD } */
        return 0;
}

int main()
{
        fff(/*PL join(", ", @list) */);

        return 0;
}
$ perl -ne '
>     print q(print q$);
>     s/\/\*PLD\s+(.*?)\s+\*\//\$; $1; print q\$/g;
>     s/\/\*PL\s+(.*?)\s+\*\//\$; print $1; print q\$/g;
>     print;
>     print q($;);
> ' < main.cpp.tmpl | perl > main.cpp
$ g++ main.cpp
$ ./a.exe
9
8
7
6
5
4
3
2
1
$
やはりここは男らしくm4で書くべきか。
>3
やっていることはmain.cpp.tmplをperlに通してその結果をもう一度perlに通してmain.cppに出力して、main.cppをコンパイルしていることはわかるのですが、

私の環境では実行できません。


>perl -ne '
ここの部分を入力すると次のようなエラーをはきます。
>Can't find string terminator "'" anywhere before EOF at -e line 1.

以下私のperlの環境
>This is perl, v5.6.1 built for MSWin32-x86-multi-thread
Perlのバージョンによって異なるというより、
Shellもしくはコマンドプロンプトの違いでしょうかね。
失敗するのはcsh系かな?
改行の前にバックスラッシュ'\'を入れてみて下さい。

うまくいかない場合はずらずらと1行に並べちゃいましょう。
まぁ、そんなことをするくらいならファイルにしてしまうのが無難ですかね。
Makefileの中で記述しようとするとまたエスケープを考えないといけないですし。

perl -n hoge.pl < main.cpp.tmpl | perl > main.cpp
./hoge.pl < main.cpp.tmpl > main.cpp
で済ませたい場合は、hoge.plの中身はこんな感じになります。

#! /usr/bin/env perl

my $code = '';
while (<>) {
    $code .= 'print q$';
    s/\/\*PLD\s+(.*?)\s+\*\//\$; $1; print q\$/g;
    s/\/\*PL\s+(.*?)\s+\*\//\$; print $1; print q\$/g;
    $code .= $_;
    $code .= '$;';
}
eval $code;
die $@ if $@;
> 3

> ' < main.cpp.tmpl | perl | g++ -x c++ -
$ ./a.out

-x c++という技を教えてもらいました。
これで標準入力から直接読み込めます。

後は、g++の出力を標準出力にしてパイプで渡し、
さらに標準入力から読み込んだデータを実行するようなプログラムを作れば
Unixらしい美しいパイプラインになりますね。
http://mixi.jp/view_bbs.pl?id=38838759&comm_id=602606の問題をWIN32APIでやってみました。

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <windows.h>
#include <tchar.h>

struct FileAtt {
#ifdef _UNICODE
std::wstring filename;
#else
std::string filename;
#endif
enum filetype { DIRECTORY, FILE } ftype;
__int64 filesize;
};

struct file_type_less_than :
public std::binary_function<FileAtt, FileAtt, bool>
{
bool operator()(const FileAtt & lhs, const FileAtt & rhs) {
return lhs.ftype < rhs.ftype;
}
};

struct file_size_less_than :
public std::binary_function<FileAtt, FileAtt, bool>
{
bool operator()(const FileAtt & lhs, const FileAtt & rhs) {
return lhs.filesize < rhs.filesize;
}
};

class my_save :
std::unary_function<FileAtt, void> {
private:
#ifdef _UNICODE
std::wofstream & _ofs;
#else
std::ofstream & _ofs;
#endif
public:
#ifdef _UNICODE
my_save(std::wofstream & ofs) : _ofs(ofs){};
#else
my_save(std::ofstream & ofs) : _ofs(ofs){};
#endif
void operator()(FileAtt & file) {
_ofs << file.filename << std::endl;
}
};

void my_print(const FileAtt & file)
{
#ifdef _UNICODE
std::wcout << file.filename << std::endl;
#else
std::cout << file.filename << std::endl;
#endif
}

std::vector<FileAtt> fileinspect()
{
HANDLE hSearch;
WIN32_FIND_DATA fd;

hSearch = ::FindFirstFile(_T("*.*"), &fd);
if (hSearch == INVALID_HANDLE_VALUE) {
return std::vector<FileAtt>(0);
}

std::vector<FileAtt> fvec;

while (true) {
FileAtt file;
#ifdef _UNICODE
file.filename = std::wstring(fd.cFileName);
#else
file.filename = std::string(fd.cFileName);
#endif
file.ftype = fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ?
file.DIRECTORY : file.FILE;
file.filesize = 0;
file.filesize |= fd.nFileSizeLow;
file.filesize |= fd.nFileSizeHigh;
fvec.push_back(file);

if (!::FindNextFile(hSearch, &fd)) {
if (::GetLastError() == ERROR_NO_MORE_FILES) {
break;
} else {
::FindClose(hSearch);
return std::vector<FileAtt>(0);
}
}
}

::FindClose(hSearch);
return fvec;
}

int main()
{
std::vector<FileAtt> fvec = fileinspect();
if (fvec.empty()) {
return EXIT_FAILURE;
}

std::stable_sort(fvec.begin(), fvec.end(), file_type_less_than());
std::stable_sort(fvec.begin(), fvec.end(), file_size_less_than());
std::for_each(fvec.begin(), fvec.end(), &my_print);

#ifdef _UNICODE
std::wofstream ofs(L"ls.out");
#else
std::ofstream ofs("ls.out");
#endif
std::for_each(fvec.begin(), fvec.end(), my_save(ofs));

return EXIT_SUCCESS;
}
何度も失礼します。
細かい修正(主にテンプレート引数リスト)を行いました。

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <windows.h>
#include <tchar.h>

struct FileAtt {
#ifdef _UNICODE
std::wstring filename;
#else
std::string filename;
#endif
enum filetype { DIRECTORY, FILE } ftype;
unsigned __int64 filesize;
};

struct file_type_less_than :
public std::binary_function<const FileAtt &, const FileAtt &, bool>
{
bool operator()(const FileAtt & lhs, const FileAtt & rhs) const {
return lhs.ftype < rhs.ftype;
}
};

struct file_size_less_than :
public std::binary_function<const FileAtt &, const FileAtt &, bool>
{
bool operator()(const FileAtt & lhs, const FileAtt & rhs) const {
return lhs.filesize < rhs.filesize;
}
};

class my_save :
std::unary_function<const FileAtt &, void> {
private:
#ifdef _UNICODE
std::wofstream & ofs_;
#else
std::ofstream & ofs_;
#endif
public:
#ifdef _UNICODE
my_save(std::wofstream & ofs) : ofs_(ofs){};
#else
my_save(std::ofstream & ofs) : ofs_(ofs){};
#endif
void operator()(const FileAtt & file) {
ofs_ << file.filename << std::endl;
}
};

void my_print(const FileAtt & file)
{
#ifdef _UNICODE
std::wcout << file.filename << std::endl;
#else
std::cout << file.filename << std::endl;
#endif
}

std::vector<FileAtt> fileinspect()
{
HANDLE hSearch;
WIN32_FIND_DATA fd;

hSearch = ::FindFirstFile(_T("*.*"), &fd);
if (hSearch == INVALID_HANDLE_VALUE) {
return std::vector<FileAtt>(0);
}

std::vector<FileAtt> fvec;

while (true) {
FileAtt file;
#ifdef _UNICODE
file.filename = std::wstring(fd.cFileName);
#else
file.filename = std::string(fd.cFileName);
#endif
file.ftype = fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ?
file.DIRECTORY : file.FILE;
file.filesize = 0;
file.filesize |= fd.nFileSizeLow;
file.filesize |= fd.nFileSizeHigh;
fvec.push_back(file);

if (!::FindNextFile(hSearch, &fd)) {
if (::GetLastError() == ERROR_NO_MORE_FILES) {
break;
} else {
::FindClose(hSearch);
return std::vector<FileAtt>(0);
}
}
}

::FindClose(hSearch);
return fvec;
}

int main()
{
std::vector<FileAtt> fvec = fileinspect();
if (fvec.empty()) {
return EXIT_FAILURE;
}

std::stable_sort(fvec.begin(), fvec.end(), file_type_less_than());
std::stable_sort(fvec.begin(), fvec.end(), file_size_less_than());
std::for_each(fvec.begin(), fvec.end(), &my_print);

#ifdef _UNICODE
std::wofstream ofs(L"ls.out");
#else
std::ofstream ofs("ls.out");
#endif
std::for_each(fvec.begin(), fvec.end(), my_save(ofs));

return EXIT_SUCCESS;
}
> [mixi] C/C++の課題丸投げ | forkで作る〜プログラム〜
> http://mixi.jp/view_bbs.pl?id=38972172&comment_count=6&comm_id=602606

もう少し簡潔に書けたなあと。

#include <sys/types.h>
#include <sys/wait.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int proc(int k, int n, const char **msgs)
{
    if (k + 1 < n) {
        pid_t cpid;

        if ((cpid = fork()) == -1)
            return EXIT_FAILURE;

        if (cpid == 0)
            _exit(proc(k + 1, n, msgs));

        if (waitpid(cpid, NULL, 0) == -1)
            return EXIT_FAILURE;
    }

    puts(msgs[k]);
    return EXIT_SUCCESS;
}

int main(void)
{
    const char *msgs[] = {
        "Parent",
        "Child",
        "Grandchild",
        "Great-grandchild"
    };
    const int n = sizeof(msgs) / sizeof(msgs[0]);

    return proc(0, n, msgs);
}
>paleman様
WIN32APIにもプロセスを生成するCreateProcessという関数があるようですので、WIN32に移植してみます。
boost版です。ディレクトリかファイルかを表示するようにしてあります。
せっかくboostを使っているので、boost::bindを使ってみました。

#include <iostream>
#include <fstream>
#include <algorithm>
#include <functional>
#include <iterator>
#include <string>
#include <vector>
#include "boost/filesystem/path.hpp"
#include "boost/filesystem/operations.hpp"
#include "boost/bind.hpp"
#include "boost/cast.hpp"

struct FileAtt {
std::string filename;
enum filetype { DIRECTORY, FILE } ftype;
unsigned __int64 filesize;
};

struct file_info_store :
public std::unary_function<const boost::filesystem::path &, FileAtt>
{
FileAtt operator()(const boost::filesystem::path & p) const {
FileAtt file;

file.filename = p.string();
if (boost::filesystem::is_directory(p)) {
file.ftype = file.DIRECTORY;
file.filesize = 0;
} else {
file.ftype = file.FILE;
file.filesize = boost::numeric_cast<unsigned __int64>(boost::filesystem::file_size(p));
}

return file;
}
};

class my_out :
public std::unary_function<const FileAtt &, void>
{
private:
std::ostream_iterator<std::string> & out_;
public:
my_out(std::ostream_iterator<std::string> & out) : out_(out){};
void operator()(const FileAtt & file) {
std::string outstr = file.ftype ? "[file] " : "[dir] ";
out_ = outstr + file.filename;
}
};

std::vector<FileAtt> fileinspect()
{
using namespace boost::filesystem;
path dir = current_path();

std::vector<FileAtt>::size_type size;
directory_iterator tbegin(dir), end;
size = boost::numeric_cast<std::vector<FileAtt>::size_type>(std::distance(tbegin, end));

std::vector<FileAtt> fvec(size);
directory_iterator begin(dir);
std::transform(begin, end, fvec.begin(), file_info_store());

return fvec;
}

int main()
{
std::vector<FileAtt> fvec(fileinspect());
if (fvec.empty()) {
return EXIT_FAILURE;
}

std::stable_sort(fvec.begin(), fvec.end(),
boost::bind(std::less<unsigned __int64>(),
boost::bind(&FileAtt::ftype, _1),
boost::bind(&FileAtt::ftype, _2)));
std::stable_sort(fvec.begin(), fvec.end(),
boost::bind(std::less<unsigned __int64>(),
boost::bind(&FileAtt::filesize, _1),
boost::bind(&FileAtt::filesize, _2)));

std::ostream_iterator<std::string> out(std::cout, "\n");
std::for_each(fvec.begin(), fvec.end(), my_out(out));

std::ofstream ofs("ls.out");
std::ostream_iterator<std::string> fout(ofs, "\n");
std::for_each(fvec.begin(), fvec.end(), my_out(fout));

return EXIT_SUCCESS;
}

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

Programming Sandbox 更新情報

Programming Sandboxのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。