我已经扫描了答案,但......他们似乎是个愚蠢的问题。
我非常满意并完全理解(我不能强调这一点),为什么拥有一个类的模板虚拟成员毫无意义。
考虑抽象基类List
(有...... LinkedList
和ArrayList
从中派生出来)
如果list存储的类型有一个identity的概念(不是字符串或int,没有任何明智的东西“==”,我不会把POD带到这里)你会想要一个方法
virtual bool contains(T& what) const;
和
virtual int index(T& what) const;
但是如果它是一个没有身份的类型,比如你想要的字符串或数字:
virtual int countOccurrences(T& what) const;
和
virtual int find(T& what, int occurrence=0) const;
说。
使用::std::enable_if
无法完成此操作,因此您必须执行以下操作:
template<class T, bool HAS_IDENTITY> class List;
template<class T> class List<false> {
virtual int countOccurrences(T& what) const=0;
virtual int find(T& what, int occurrence=0) const=0;
/*other stuff*/
};
template<class T> class List<true> {
virtual bool contains(T& what) const =0;
virtual int index(T& what) const =0;
/*other stuff*/
};
这并不是那么糟糕,但是有很多代码重复,而且只有在必要的时候才会弄湿(反对DRY)。
如果我将公共代码隐藏在基类中,那就更好了。
我的问题涉及使用这种方法缩放,这里我们有一个bool,给出2个特化,假设我有n个bool然后有2 ^ n个特化,我看不到我需要超过4个的情况,但这仍然涉及16个课程! 8比3,这不是很好。
假设我有一个enum和一个bool,那么我有2 * enum count专长。
它快速增长。
以前我们已经使用宏来定义类,并且它在类名中使用##
运算符来实际上将其作为模板进行修改。我必须说虽然我现在非常喜欢enable_if
和朋友......
是否有某种模式可以让我告诉我解决这个问题?
答案 0 :(得分:1)
只是一个q&amp; d hack,但它应该提供一些提示。
我知道一个人甚至可以摆脱那个丑陋的&#34; Dummy&#34; param,但我现在没有看到
编辑7月6日
我使ansatz使用起来更加无缝。 概念&#34;身份&#34;的编译时测试,问题揭幕者显然是针对什么,需要编译时测试
//T t1, t2;
(t1 == t2) == (&t1 == &t2);
这是不可能的。 因此,我介绍了功能列表的概念,以便于手动分配这些功能。
#include <iostream>
#include <typeinfo>
#include <type_traits>
#ifdef __GNUG__
#include <cxxabi.h>
auto type_str = [](const std::type_info& ti) {
int stat;
return abi::__cxa_demangle(ti.name(), 0, 0, &stat);
};
#else
#warning untested
auto type_str = [](const std::type_info& ti) {
return ti.name();
};
#endif
typedef int Feature;
const Feature HAS_IDENTITY = 1;
const Feature HAS_FOOBAR = 2;
const Feature HAS_NO_IDENTITY = -HAS_IDENTITY;
const Feature HAS_NO_FOOBAR = -HAS_FOOBAR;
const Feature _TERM_ = 0;
template<typename T, Feature F>
struct has_feature : std::false_type {};
template<int N , int M>
struct is_greater {
constexpr static bool value = N > M;
};
namespace detail {
template<class T, Feature... Fs> struct List {}; // primary template
template<class T, Feature F>
struct List<T,F> {};
template<class T, Feature F, Feature... Fs>
struct List<T,F,Fs...>
: virtual public
std::conditional<
has_feature<T,F>::value,
List<T, F>,
List<T, -F>
>::type,
virtual public
std::conditional<
is_greater<sizeof...(Fs),0>::value,
List<T, Fs...>,
List<T, _TERM_>
> ::type {};
template<class T> struct List<T, _TERM_> {};
template<class T>
struct List<T,HAS_NO_FOOBAR> {
virtual std::string hello() const /* = 0;*/ {
return std::string("\"What the foo is FOOBAR?\", askes ") + type_str(typeid(T));
}
};
template<class T>
struct List<T,HAS_FOOBAR> {
virtual std::string hello() const /* = 0;*/ {
return std::string("\"For sure I'm FOOBAR\", says ") + type_str(typeid(T));
}
};
template<class T>
struct List<T,HAS_NO_IDENTITY> {
virtual int index(const T& what) const /* = 0;*/ {
return 137;
}
};
template<class T>
struct List<T,HAS_IDENTITY> {
virtual int index(const T& what) const /* = 0;*/ {
return 42;
}
};
template<typename T>
using Feature_Aware_List = List<T,HAS_IDENTITY,HAS_FOOBAR, /* all Features incuding*/_TERM_>;
} //namespace detail
template<typename T>
using List = detail::Feature_Aware_List<T>;
struct Gadget {
bool operator== (const Gadget& rhs) const {
return this == &rhs;
}
};
struct Gimmick {
bool operator== (const Gimmick& rhs) const {
return this == &rhs;
}
};
template<Feature F>
struct FeatureList {};
template<>
struct FeatureList<HAS_IDENTITY>
: public Gadget,
public Gimmick
/**/
{};
#include <valarray>
template<>
struct FeatureList<HAS_FOOBAR>
: public std::valarray<float>
/**/
{};
template<class T>
struct has_feature<T, HAS_IDENTITY>
: public std::conditional<
std::is_base_of<T, FeatureList<HAS_IDENTITY>>::value,
std::true_type,
std::false_type
>::type {};
template<class T>
struct has_feature<T, HAS_FOOBAR>
: public std::conditional<
std::is_base_of<T, FeatureList<HAS_FOOBAR>>::value,
std::true_type,
std::false_type
>::type {};
int main() {
List<Gadget> l1 ;
List<std::valarray<float>> l2;
std::cout << l1.hello() << " #" << l1.index(Gadget()) << std::endl;
std::cout << l2.hello() << " #" << l2.index(std::valarray<float>()) << std::endl;
}
输出:
"What the foo is FOOBAR?", askes Gadget #42
"For sure I'm FOOBAR", says std::valarray<float> #137
应该是自我解释,没有具体的&#34;列表&#34;实现了功能,这只是模拟
答案 1 :(得分:1)
您可以使用模板政策:
template<class T, bool HAS_IDENTITY> class ListIdentityPolicy;
template<class T> class ListIdentityPolicy<T, false> {
virtual int countOccurrences(T& what) const = 0;
virtual int find(T& what, int occurrence = 0) const = 0;
};
template<class T> class ListIdentityPolicy<T, true> {
virtual bool contains(T& what) const = 0;
virtual int index(T& what) const = 0;
};
template<class T, bool HAS_FOOBAR> struct ListFoobarPolicy;
template<class T> struct ListFoobarPolicy<T, false> {
virtual void foo() = 0;
};
template<class T> struct ListFoobarPolicy<T, true> {
virtual void bar() = 0;
};
template <class T> class List
: public ListIdentityPolicy<T, HasIdentity<T>::value>
, public ListFoobarPolicy<T, HasFoobar<T>::value>
{
public:
/*other stuff*/
};
HasIdentity
和HasFoobar
是您要定义的类型特征,每个特征都包含一个static const bool value
,表示T
是否具有相应的属性。
或者,您可以为List
提供非虚拟公共API,并在实现中隐藏动态分派:
template <class T> class List
{
public:
enum Impl {
LinkedList = 0,
ArrayList,
};
List(Impl i) : pimpl(makePimpl(i)) {}
List(List const& other) : pimpl(other.pimpl->clone())
List& operator=(List const& other) { pimpl = other.pimpl->clone(); }
int count(T& what) const
{ static_assert(! HasIdentity<T>::value, "oops"); return pimpl->count(what); }
int find(T& what, int n = 0) const
{ static_assert(! HasIdentity<T>::value, "oops"); return pimpl->find(what, n); }
bool contains(T& what) const
{ static_assert(HasIdentity<T>::value, "oops"); return pimpl->contains(what); }
int index(T& what) const
{ static_assert(HasIdentity<T>::value, "oops"); return pimpl->index(what); }
void foo()
{ static_assert(! HasFoobar<T>::value, "oops"); pimpl->foo(); }
void bar()
{ static_assert(HasFoobar<T>::value, "oops"); pimpl->bar(); }
private:
struct AbstractPimpl
{
virtual std::unique_ptr<AbstractPimpl> clone() const = 0;
virtual int count(T& what) const = 0;
virtual int find(T& what, int n = 0) const = 0;
virtual bool contains(T& what) const = 0;
virtual int index(T& what) const = 0;
virtual void foo() = 0;
virtual void bar() = 0;
};
struct LinkedListPimpl : public AbstractPimpl
{
std::unique_ptr<AbstractPimpl> clone() override;
int count(T& what) const override;
int find(T& what, int n = 0) const override;
bool contains(T& what) const override;
int index(T& what) const override;
void foo() override;
void bar() override;
/* ... */
};
struct ArrayListPimpl : public AbstractPimpl
{
std::unique_ptr<AbstractPimpl> clone() override;
virtual int count(T& what) const override;
virtual int find(T& what, int n = 0) const override;
virtual bool contains(T& what) const override;
virtual int index(T& what) const override;
virtual void foo() override;
virtual void bar() override;
/* ... */
};
std::unique_ptr<AbstractPimpl> pimpl;
static std::unique_ptr<AbstractPimpl> makePimpl(Impl i) {
switch (i) {
LinkedList: default:
return std::make_unique<LinkedListPimpl>();
ArrayList:
return std::make_unique<ArrayListPimpl>();
}
}
};