zxc さんが書きました:
- TがWrap<U>型であるというパターンを識別する方法は?
- TがWrap<U>であるWrap<T>に対して特別な処理を行う
- 受け取ったTがWrap<U> 型である場合とそうでない場合でWrap<T>クラスの振る舞いをわける方法
が知りたいです。
再起処理を含めたあまり良い説明が思いつかなかったので、質問内容とは少し異なりますがサンプルコードを載せておきます。理解へのきっかけとなれば幸いです。
下記のコードは、ファイルから1行読み込み、カンマに区切られた各単語を指定した型へキャストしてtupleに格納するコードです。
tuple.hppの
116行目 token_cast_::set 関数で再帰処理
121行目 token::get 関数で型毎に振る舞いを分けています。
各型に対する特別な処理として stoiなど文字列から各型への変換を使用しています。
即席で書いたものなので、処理が適当なのはご容赦ください。
Main.cpp
コード:
#include <iostream>
#include <fstream>
#include <string>
#include "tuple.hpp"
using namespace std;
int main()
{
ifstream ifs("test.ini");
if (ifs)
{
string line;
if (getline(ifs, line))
{
//12,40,13,40,C:\Users\Public\Downloads\test.txt
auto tuple = getTuple<int, int, int, int, string>(line, ',');
if (isOK(tuple))
{
cout << token(tuple, 1) << endl;
cout << token(tuple, 2) << endl;
cout << token(tuple, 3) << endl;
cout << token(tuple, 4) << endl;
cout << token(tuple, 5) << endl;
}
}
if (getline(ifs, line))
{
// (※空行:\s\t\t\s) 空行のため isOK(tuple)は falseを返すので表示はない。
auto tuple = getTuple<int, int, int, int, string>(line, ',');
if (isOK(tuple))
{
cout << token(tuple, 1) << endl;
cout << token(tuple, 2) << endl;
cout << token(tuple, 3) << endl;
cout << token(tuple, 4) << endl;
cout << token(tuple, 5) << endl;
}
}
if (getline(ifs, line))
{
//0.57, こんにちは
auto tuple = getTuple<double, string>(line, ',');
if (isOK(tuple))
{
cout << token(tuple, 1) << endl;
cout << token(tuple, 2) << endl;
}
}
if (getline(ifs, line))
{
//東京都特許許可局, 2, 0.112
auto tuple = getTuple<string, int, float>(line, ',');
if (isOK(tuple))
{
cout << token(tuple, 1) << endl;
cout << token(tuple, 2) << endl;
cout << token(tuple, 3) << endl;
}
}
if (getline(ifs, line))
{
//ABC, DEF, 0.57, 3 (4つの内、前3つを取り出す)
auto tuple = getTuple<string, string, double>(line, ',');
if (isOK(tuple))
{
cout << token(tuple, 1) << endl;
cout << token(tuple, 2) << endl;
cout << token(tuple, 3) << endl;
}
}
}
ifs.close();
cout << endl << "press any key to continue..." << endl;
cin.ignore();
return 0;
}
tuple.hpp
コード:
#pragma once
#include <stdexcept>
#include <iostream>
#include <sstream>
#include <string>
#include <regex>
#include <tuple>
#include <vector>
#include <cstdint>
#define isOK(pair) pair.first
#define token(pair, i) std::get<i-1>(pair.second)
template<std::size_t index, typename Token_Type>
struct token
{
static inline Token_Type get(std::vector<std::string>& token_list, std::size_t& token_index)
{
throw std::logic_error("not implemented type: " + std::string(typeid(Token_Type).name()));
}
};
template<std::size_t index>
struct token<index, std::int32_t>
{
static inline std::int32_t get(std::vector<std::string>& token_list, std::size_t& token_index)
{
std::size_t idx;
auto value = stoi(token_list[index], &idx, 10);
if (idx != token_list[index].size()) throw std::bad_cast();
token_index--;
return value;
}
};
template<std::size_t index>
struct token<index, std::uint32_t>
{
static inline std::uint32_t get(std::vector<std::string>& token_list, std::size_t& token_index)
{
std::size_t idx;
auto value = stoul(token_list[index], &idx, 10);
if (idx != token_list[index].size()) throw std::bad_cast();
token_index--;
return value;
}
};
template<std::size_t index>
struct token<index, std::int64_t>
{
static inline std::int64_t get(std::vector<std::string>& token_list, std::size_t& token_index)
{
std::size_t idx;
auto value = stoll(token_list[index], &idx, 10);
if (idx != token_list[index].size()) throw std::bad_cast();
token_index--;
return value;
}
};
template<std::size_t index>
struct token<index, std::uint64_t>
{
static inline std::uint64_t get(std::vector<std::string>& token_list, std::size_t& token_index)
{
std::size_t idx;
auto value = stoull(token_list[index], &idx, 10);
if (idx != token_list[index].size()) throw std::bad_cast();
token_index--;
return value;
}
};
template<std::size_t index>
struct token<index, float>
{
static inline float get(std::vector<std::string>& token_list, std::size_t& token_index)
{
std::size_t idx;
auto value = stof(token_list[index], &idx);
if (idx != token_list[index].size()) throw std::bad_cast();
token_index--;
return value;
}
};
template<std::size_t index>
struct token<index, double>
{
static inline double get(std::vector<std::string>& token_list, std::size_t& token_index)
{
std::size_t idx;
auto value = stod(token_list[index], &idx);
if (idx != token_list[index].size()) throw std::bad_cast();
token_index--;
return value;
}
};
template<std::size_t index>
struct token<index, std::string>
{
static inline std::string get(std::vector<std::string>& token_list, std::size_t& token_index)
{
token_index--;
return token_list[index];
}
};
template<std::size_t index, typename Tuple_Type>
struct token_cast_
{
static inline void set(Tuple_Type &tuple, std::vector<std::string>& token_list, std::size_t& token_index)
{
using Token_Type = typename std::tuple_element<index, Tuple_Type>::type;
std::get<index>(tuple) = token<index, Token_Type>::get(token_list, token_index);
token_cast_<index - 1, Tuple_Type>::set(tuple, token_list, token_index);
}
};
template<typename Tuple_Type>
struct token_cast_<0, Tuple_Type>
{
static inline void set(Tuple_Type &tuple, std::vector<std::string>& token_list, std::size_t& token_index)
{
using Token_Type = typename std::tuple_element<0, Tuple_Type>::type;
std::get<0>(tuple) = token<0, Token_Type>::get(token_list, token_index);
}
};
template<typename Tuple_Type>
struct token_cast
{
static inline void set(Tuple_Type &tuple, std::vector<std::string>& token_list, std::size_t& token_index)
{
token_cast_<std::tuple_size<Tuple_Type>::value - 1, Tuple_Type>::set(tuple, token_list, token_index);
}
};
template<typename... Tuple_Type>
static inline std::tuple<Tuple_Type...> getTuple(std::vector<std::string>& token_list, std::size_t& token_index)
{
using Tuple = std::tuple<Tuple_Type...>;
Tuple tuple;
token_index = std::tuple_size<Tuple>::value;
if (token_index > token_list.size()) throw std::out_of_range("tuple index out of range");
token_cast<Tuple>::set(tuple, token_list, token_index);
return move(tuple);
}
static inline std::string& trim(std::string& s)
{
s.erase(std::begin(s), std::find_if_not(std::begin(s), std::end(s), [](const char& c){ return isspace(static_cast<unsigned char>(c)); }));
s.erase(std::find_if_not(s.rbegin(), s.rend(), [](const char& c){ return isspace(static_cast<unsigned char>(c)); }).base(), std::end(s));
return s;
}
static inline std::vector<std::string> split(const std::string& s, const char separator)
{
std::vector<std::string> v;
std::istringstream iss(s);
std::string token;
while (std::getline(iss, token, separator)) v.emplace_back(trim(token));
return std::move(v);
}
template<typename... Tuple_Type>
static inline std::pair<bool, std::tuple<Tuple_Type...>> getTuple(std::string line, const char separator)
{
using Tuple = std::tuple<Tuple_Type...>;
Tuple tuple;
bool result = false;
std::size_t token_index = -1;
if (line[line.size() - 1] == '\r') line.resize(line.size() - 1);
if (trim(line).size() > 0)
{
try
{
auto token_list = split(line, separator);
tuple = getTuple<Tuple_Type...>(token_list, token_index);
result = true;
}
catch (std::bad_cast& ex)
{
std::cerr << "Error: " << ex.what() << std::endl;
std::cerr << "Type: " << typeid(ex).name() << std::endl;
std::cerr << "token: " << token_index << std::endl;
}
catch (std::invalid_argument& ex)
{
std::cerr << "Error: " << ex.what() << std::endl;
std::cerr << "Type: " << typeid(ex).name() << std::endl;
std::cerr << "token: " << token_index << std::endl;
}
catch (std::out_of_range& ex)
{
std::cerr << "Error: " << ex.what() << std::endl;
std::cerr << "Type: " << typeid(ex).name() << std::endl;
std::cerr << "token: " << token_index << std::endl;
}
catch (std::exception& ex)
{
std::cerr << "Error: " << ex.what() << std::endl;
std::cerr << "Type: " << typeid(ex).name() << std::endl;
}
}
return std::make_pair(result, tuple);
}
test.ini
コード:
12,40,13,40,C:\Users\Public\Downloads\test.txt
0.57, こんにちは
東京都特許許可局, 2, 0.112
ABC, DEF, 0.57, 3