OPの目標をよりよく理解した上で、新しい回答を追加します。私の最初の答えは、いくつかのサンプルコードをコンパイルするときに遭遇する依存テンプレートの型パラメータに関連する問題を扱ったので、それはまだ有効な答えだと思います。
この回答は、カスタムコンテナクラスを作成する方法と、コンテナを反復処理し、各要素に対してカスタム関数オブジェクトを呼び出し、各結果を関数によって最後に返された別のコンテナに追加する汎用関数の記述方法を示しています。
この例のコンテナは、最低限のフィーチャセットで定義されたリンクリストです。この例では、コンパイルおよび実行に十分です。
リンクリストクラスは、リストをトラバースするために使用されるイテレータオブジェクトを返すbegin()
およびend()
関数を提供します。ここでは定数でないバージョンだけが定義されていますが、LinkedListオブジェクトがconstの場合には定数の反復子を返すバージョンも追加する必要があります。
ここでは、関数Map
はファンクタとコンテナオブジェクトを引数として取ります。すべての引数型が導出されるので、テンプレートパラメータを明示的に指定する必要はありません。コンテナはLinkedListのconst正当性の問題を避けるために値渡しされます。また、LinkedList
(デフォルト)のコピーコンストラクタは多くの作業を行わないため、オブジェクトを2つだけコピーする必要はありません。含まれているすべてのデータの完全コピー。
Map
これは非常に単純で、追加の改良されたバージョンは2つのイテレータ(開始と終了)を取り、コンテナオブジェクトへのconst参照を(無駄なコピーを避けるため)取るか、または型の特性を使用して特別な方法でアクセスできます。
Map
は、標準イテレータAPIを使用しているため、std :: vectorなどの他のコンテナで動作する必要があります。
元のバージョンのLinkedListは、ただ1つのリストノードへのポインタとして維持されていました。以下のコードでは、LinkedList
は、最初と最後のNode
オブジェクトへの(スマートな)ポインタを保持する実際のコンテナオブジェクトです。ここでは、head
とtail
の両方のノードへのポインタにアクセスする必要があるため、1つのノードへのポインタを保持することは不十分です。
#include <iostream>
#include <memory>
#include <string>
template<typename T>
class LinkedList {
public:
struct Node;
using NodeType = std::shared_ptr<Node>;
struct Node {
NodeType next;
T value;
};
class forward_iterator {
NodeType cur_node;
public:
forward_iterator() {}
forward_iterator(NodeType cur_node) : cur_node(cur_node) {}
T& operator *() { return cur_node->value; }
forward_iterator& operator ++() { cur_node = cur_node->next; return *this; }
bool operator == (const forward_iterator& it) const { return cur_node == it.cur_node; }
bool operator != (const forward_iterator& it) const { return !operator == (it); }
};
void push_back(const T& t) {
NodeType node = std::make_shared<Node>();
if(tail) {
tail->next = node;
tail = node;
} else {
head = tail = node;
}
node->value = t;
}
forward_iterator begin() { return forward_iterator(head); }
forward_iterator end() { return forward_iterator(); }
protected:
NodeType head, tail;
};
inline std::string upper_case(const std::string& s) {
std::string r;
for(auto c : s) {
if(c >= 'a' && c <= 'z') c = c - 'a' + 'A';
r.push_back(c);
}
return r;
}
template <typename Func, typename S>
inline S Map(Func func, S seq) {
S result;
for(const auto& elem : seq) {
result.push_back(func(elem));
}
return result;
}
int main() {
// add strings to a LinkedList of strings named "original"
static const char* my_data[] = { "Hello", "1234", "John Cena", "xd" };
LinkedList<std::string> original;
for(auto cstr : my_data) { original.push_back(cstr); }
// dump "original" to cout
std::cout << "-- original --\n";
for(const auto& s : original) { std::cout << s << '\n'; }
std::cout << '\n';
// Run the generic Map function with "original" as input
// A lambda will be called for each element and
// its returned value added to the result, named "mapped".
// A functor object may be used in place of the lambda
auto mapped = Map(
[](const std::string& s) { return upper_case(s); },
original);
// dump "mapped" to cout
std::cout << "-- mapped --\n";
for(const auto& s : mapped) { std::cout << s << '\n'; }
std::cout << '\n';
}
あなたは、コンパイラに 'Func = int'ここで' Map(p、one) 'と言っています。 ' –
Praetorian
' auto result = Map(p、one); 'これは' print'を 'int'に参照しようとしていませんか? –
AchmadJP
テンプレートパラメータを入れ替えた場合、 'Map(p、one)'を指定し、 'Func'を' Print'として推測させることができます。 –
melak47