我想要一个基类
Collection
定义以下接口。基类本身不应该实现这些数据,而是所有这些数据都应该由子类提供。
A型
Member
静态函数
Member first_object()
静态函数
Member last_object()
静态函数
std::vector<Member> all_objects()
我的问题是我不知道如何拥有一个具有子类提供的类型的基类,即问题在于
Member
类型。
我能够提出以下实现(完整代码位于帖子底部):
template <typename Member>
struct CollectionBase {
static Member first_object();
static Member last_object();
static std::vector<Member> all_objects();
};
struct CollectionA : CollectionBase<int> {
public:
using Member = int;
private:
static std::vector<Member> const objects;
public:
static Member first_object() {
return objects.front();
}
static Member last_object() {
return objects.back();
}
static std::vector<Member> all_objects() {
return objects;
}
};
std::vector<CollectionA::Member> const CollectionA::objects = {1, 2, 3};
struct CollectionB : CollectionBase<std::string> {
public:
using Member = std::string;
private:
static std::vector<Member> const objects;
public:
static Member first_object() {
return objects.front();
}
static Member last_object() {
return objects.back();
}
static std::vector<Member> all_objects() {
return objects;
}
};
std::vector<CollectionB::Member> const CollectionB::objects = {"One", "Two", "Three"};
template <typename Collection>
void do_stuff() {
typename Collection::Member first_object = Collection::first_object();
typename Collection::Member last_object = Collection::last_object();
std::vector<typename Collection::Member> all_objects = Collection::all_objects();
std::cout
<< "First object: " << first_object << std::endl
<< "Last object: " << last_object << std::endl
<< "All objects: " << all_objects << std::endl
;
}
int main() {
do_stuff<CollectionA>();
do_stuff<CollectionB>();
}
输出:
First object: 1
Last object: 3
All objects: { 1, 2, 3 }
First object: One
Last object: Three
All objects: { One, Two, Three }
这种行为正是我想要的。但是,我对必须始终手动传递
Member
类型参数感到不满意。事实上,在我的实际应用中,我有两种类型,这会变得很麻烦。
如果我的代码看起来有点类似于以下代码,我会更喜欢它:
struct CollectionBase {
static typename Member;
static Member first_object();
static Member last_object();
static std::vector<Member> all_objects();
};
struct CollectionA : CollectionBase {
public:
using Member = int;
private:
static std::vector<Member> const objects;
public:
static Member first_object() {
return objects.front();
}
static Member last_object() {
return objects.back();
}
static std::vector<Member> all_objects() {
return objects;
}
};
std::vector<CollectionA::Member> const CollectionA::objects = {1, 2, 3};
struct CollectionB : CollectionBase {
public:
using Member = std::string;
private:
static std::vector<Member> const objects;
public:
static Member first_object() {
return objects.front();
}
static Member last_object() {
return objects.back();
}
static std::vector<Member> all_objects() {
return objects;
}
};
std::vector<CollectionB::Member> const CollectionB::objects = {"One", "Two", "Three"};
template <typename Collection>
void do_stuff() {
typename Collection::Member first_object = Collection::first_object();
typename Collection::Member last_object = Collection::last_object();
std::vector<typename Collection::Member> all_objects = Collection::all_objects();
std::cout
<< "First object: " << first_object << std::endl
<< "Last object: " << last_object << std::endl
<< "All objects: " << all_objects << std::endl
;
}
int main() {
do_stuff<CollectionA>();
do_stuff<CollectionB>();
}
为了强调,这里是
git diff
:
@@ -1,11 +1,11 @@
-template <typename Member>
struct CollectionBase {
+ static typename Member;
static Member first_object();
static Member last_object();
static std::vector<Member> all_objects();
};
-struct CollectionA : CollectionBase<int> {
+struct CollectionA : CollectionBase {
public:
using Member = int;
private:
@@ -24,7 +24,7 @@ public:
std::vector<CollectionA::Member> const CollectionA::objects = {1, 2, 3};
-struct CollectionB : CollectionBase<std::string> {
+struct CollectionB : CollectionBase {
public:
using Member = std::string;
private:
可以这样做吗?
完整的工作示例(GodBolt Link):
#include <string>
#include <vector>
#include <iostream>
template <typename T>
std::ostream& operator<<(std::ostream& os, std::vector<T> const& v)
{
os << "{ ";
bool first = true;
for (T const& t : v) {
if (first)
first = false;
else
os << ", ";
os << t;
}
os << " }";
return os;
}
template <typename Member>
struct CollectionBase {
static Member first_object();
static Member last_object();
static std::vector<Member> all_objects();
};
struct CollectionA : CollectionBase<int> {
public:
using Member = int;
private:
static std::vector<Member> const objects;
public:
static Member first_object() {
return objects.front();
}
static Member last_object() {
return objects.back();
}
static std::vector<Member> all_objects() {
return objects;
}
};
std::vector<CollectionA::Member> const CollectionA::objects = {1, 2, 3};
struct CollectionB : CollectionBase<std::string> {
public:
using Member = std::string;
private:
static std::vector<Member> const objects;
public:
static Member first_object() {
return objects.front();
}
static Member last_object() {
return objects.back();
}
static std::vector<Member> all_objects() {
return objects;
}
};
std::vector<CollectionB::Member> const CollectionB::objects = {"One", "Two", "Three"};
template <typename Collection>
void do_stuff() {
typename Collection::Member first_object = Collection::first_object();
typename Collection::Member last_object = Collection::last_object();
std::vector<typename Collection::Member> all_objects = Collection::all_objects();
std::cout
<< "First object: " << first_object << std::endl
<< "Last object: " << last_object << std::endl
<< "All objects: " << all_objects << std::endl
;
}
int main() {
do_stuff<CollectionA>();
do_stuff<CollectionB>();
}
输出:
First object: 1
Last object: 3
All objects: { 1, 2, 3 }
First object: One
Last object: Three
All objects: { One, Two, Three }
CollectionBase
课程根本没有必要。下面的代码也可以工作(GodBolt Link):
#include <string>
#include <vector>
#include <iostream>
template <typename T>
std::ostream& operator<<(std::ostream& os, std::vector<T> const& v)
{
os << "{ ";
bool first = true;
for (T const& t : v) {
if (first)
first = false;
else
os << ", ";
os << t;
}
os << " }";
return os;
}
struct CollectionA {
public:
using Member = int;
private:
static std::vector<Member> const objects;
public:
static Member first_object() {
return objects.front();
}
static Member last_object() {
return objects.back();
}
static std::vector<Member> all_objects() {
return objects;
}
};
std::vector<CollectionA::Member> const CollectionA::objects = {1, 2, 3};
struct CollectionB {
public:
using Member = std::string;
private:
static std::vector<Member> const objects;
public:
static Member first_object() {
return objects.front();
}
static Member last_object() {
return objects.back();
}
static std::vector<Member> all_objects() {
return objects;
}
};
std::vector<CollectionB::Member> const CollectionB::objects = {"One", "Two", "Three"};
template <typename Collection>
void do_stuff() {
typename Collection::Member first_object = Collection::first_object();
typename Collection::Member last_object = Collection::last_object();
std::vector<typename Collection::Member> all_objects = Collection::all_objects();
std::cout
<< "First object: " << first_object << std::endl
<< "Last object: " << last_object << std::endl
<< "All objects: " << all_objects << std::endl
;
}
int main() {
do_stuff<CollectionA>();
do_stuff<CollectionB>();
}