在可变参数上使用声明。如何选择正确的功能?
Using declaration on variadic args. How to choose the correct function?
我有一个基于策略的设计,其中我有一些功能 foo()
在某些策略中定义,但在其他策略中没有定义。基础 class 总是继承自一些名为 AlwaysBase
的 class,它具有较差的 foo()
功能。
我想做到这一点,如果存在“更好的”foo()
(一个来自政策 class),那么将始终选择一个。
这是一些代码:
// logic for determining if a class has a member function (not really related)
template <class> struct sfinae_true: std::true_type{};
template <class T> static auto test_foo(int) -> sfinae_true<decltype(std::declval<T>().foo())>;
template <class> static auto test_foo(long) -> std::false_type;
template <class T> struct has_foo : decltype(test_foo<T>(0)){};
class AlwaysBase{ public: void foo(){ cout << "in AlwaysBase foo()" << endl; } };
class BPolicy{};
class CPolicy{ public: void foo(){ cout << "in Cpolicy foo()" << endl; } };
template<typename T, typename ...Args>
class A: public T, public A<Args...>
{
public:
using std::conditional_t<has_foo<T>::value, T, AlwaysBase>::foo;
};
template<typename T>
class A<T>: public T, public AlwaysBase
{
public:
using std::conditional_t<has_foo<T>::value, T, AlwaysBase>::foo;
};
int main()
{
A<BPolicy> b;
b.foo(); // outputs: In AlwaysBase foo()
A<CPolicy> c;
c.foo(); // outputs: In CPolicy foo()
A<CPolicy, BPolicy> cb;
cb.foo(); // outputs: In CPolicy foo()
A<BPolicy, CPolicy> bc;
bc.foo(); // outputs: In AlwaysBase foo() // I WANT THIS TO OUTPUT!!!!: In CPolicy foo
}
我明白这里发生了什么,当 BPolicy
是第一个时,using 语句首先在可变参数 class 中使用,并隐藏任何前面的 using 语句,这些语句将在终止基中找到class(即CPolicy::foo)。
我希望在指定策略时顺序无关紧要,如果一个策略有一个决定因素,那么应该总是先选择那个而不是 AlwaysBase::foo
。
使用递归。如果允许空列表,这很容易:
// recursive invariant: As<Ts...>::foo is always the foo from the first capable Ts or from AlwaysBase
template<typename... Ts>
class A : public AlwaysBase { // template<> class A<>
public:
// there are no capable Ts
using AlwaysBase::foo;
};
template<typename T, typename... Ts>
class A<T, Ts...> : public T, public A<Ts...> {
public:
// from the A<Ts...> superclass, not AlwaysBase
// try to use T, fall back to Ts, and only then fall back to AlwaysBase
using std::conditional_t<has_foo<T>::value, T, A<Ts...>>::foo;
};
限制为非空列表有点烦人:
template<typename T, typename... Ts>
class A : public T, public A<Ts...> {
public:
using std::conditional_t<has_foo<T>::value, T, A<Ts...>>::foo;
};
template<typename T>
class A<T> : public T, public AlwaysBase {
public:
using std::conditional_t<has_foo<T>::value, T, AlwaysBase>::foo;
};
不过,顺序仍然很重要。如果两个策略提供 foo
,第一个获胜。
我有一个基于策略的设计,其中我有一些功能 foo()
在某些策略中定义,但在其他策略中没有定义。基础 class 总是继承自一些名为 AlwaysBase
的 class,它具有较差的 foo()
功能。
我想做到这一点,如果存在“更好的”foo()
(一个来自政策 class),那么将始终选择一个。
这是一些代码:
// logic for determining if a class has a member function (not really related)
template <class> struct sfinae_true: std::true_type{};
template <class T> static auto test_foo(int) -> sfinae_true<decltype(std::declval<T>().foo())>;
template <class> static auto test_foo(long) -> std::false_type;
template <class T> struct has_foo : decltype(test_foo<T>(0)){};
class AlwaysBase{ public: void foo(){ cout << "in AlwaysBase foo()" << endl; } };
class BPolicy{};
class CPolicy{ public: void foo(){ cout << "in Cpolicy foo()" << endl; } };
template<typename T, typename ...Args>
class A: public T, public A<Args...>
{
public:
using std::conditional_t<has_foo<T>::value, T, AlwaysBase>::foo;
};
template<typename T>
class A<T>: public T, public AlwaysBase
{
public:
using std::conditional_t<has_foo<T>::value, T, AlwaysBase>::foo;
};
int main()
{
A<BPolicy> b;
b.foo(); // outputs: In AlwaysBase foo()
A<CPolicy> c;
c.foo(); // outputs: In CPolicy foo()
A<CPolicy, BPolicy> cb;
cb.foo(); // outputs: In CPolicy foo()
A<BPolicy, CPolicy> bc;
bc.foo(); // outputs: In AlwaysBase foo() // I WANT THIS TO OUTPUT!!!!: In CPolicy foo
}
我明白这里发生了什么,当 BPolicy
是第一个时,using 语句首先在可变参数 class 中使用,并隐藏任何前面的 using 语句,这些语句将在终止基中找到class(即CPolicy::foo)。
我希望在指定策略时顺序无关紧要,如果一个策略有一个决定因素,那么应该总是先选择那个而不是 AlwaysBase::foo
。
使用递归。如果允许空列表,这很容易:
// recursive invariant: As<Ts...>::foo is always the foo from the first capable Ts or from AlwaysBase
template<typename... Ts>
class A : public AlwaysBase { // template<> class A<>
public:
// there are no capable Ts
using AlwaysBase::foo;
};
template<typename T, typename... Ts>
class A<T, Ts...> : public T, public A<Ts...> {
public:
// from the A<Ts...> superclass, not AlwaysBase
// try to use T, fall back to Ts, and only then fall back to AlwaysBase
using std::conditional_t<has_foo<T>::value, T, A<Ts...>>::foo;
};
限制为非空列表有点烦人:
template<typename T, typename... Ts>
class A : public T, public A<Ts...> {
public:
using std::conditional_t<has_foo<T>::value, T, A<Ts...>>::foo;
};
template<typename T>
class A<T> : public T, public AlwaysBase {
public:
using std::conditional_t<has_foo<T>::value, T, AlwaysBase>::foo;
};
不过,顺序仍然很重要。如果两个策略提供 foo
,第一个获胜。