- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我有一个 Foo 类,它有两个类型为 A 和 B 的任意数据成员。对 Foo::operator()(Arg &&) 的调用将参数转发给两个成员并返回结果的总和。我可以看到几种方法来实现所有必要的类型推导。是否有一些首选方法可以减轻编译器的压力?我的意思是编译时意义上的“应变”,如果嵌套太深就会达到内部限制,等等。你能概括一下吗,或者它是否高度特定于给定的编译器?
我可以做“朴素的”auto-decltype 变体:
template <typename A, typename B>
class Foo
{
public:
Foo(A a, B b) : m_a(std::move(a)), m_b(std::move(b)) { }
template <typename Arg>
auto operator()(Arg && arg) -> decltype(m_a(std::forward<Arg>(arg)) + m_b(std::forward<Arg>(arg)))
{
return m_a(std::forward<Arg>(arg)) + m_b(std::forward<Arg>(arg));
}
private:
A m_a;
B m_b;
};
我可以编写一个辅助结构,它只对类型而不是对“真实”实例进行操作,而是对由 std::declval<> 创建的实例进行操作<>
template <typename A, typename B, typename Arg>
struct Foo_Returns
{
typedef decltype(std::declval<A>()(std::declval<Arg>()) +
std::declval<B>()(std::declval<Arg>())) type;
}
template <typename A, typename B>
class Foo
{
public:
Foo(A a, B b) : m_a(std::move(a)), m_b(std::move(b)) { }
template <typename Arg>
typename Foo_Returns<A, B, Arg>::type
operator()(Arg && arg)
{
return m_a(std::forward<Arg>(arg)) + m_b(std::forward<Arg>(arg));
}
private:
A m_a;
B m_b;
};
还有更多的可能性吗?
现在让它变得更难:我们有两个特征 is_green<> 和 is_blue<>。如果 Arg 为绿色,Foo 的 operator() 应将 Arg 转发给 A 和 B 的成员函数 green 并返回结果之和,如果 Arg 为蓝色则类似。一个类型永远不会既是绿色又是蓝色。应该可以添加额外的类型风格(因此不允许使用 bool 值来指示蓝色或绿色)。
一种变体会尽可能使用标签调度和 auto -> decltype(...):
struct green_tag { };
struct blue_tag { };
struct error_tag;
template <typename T>
struct category
{
typedef typename std::conditional<is_green<T>::value,
green_tag,
typename std::conditional<is_blue<T>::value,
blue_tag,
error_tag
>::type
>::type type;
}
template <typename A, typename B>
class Foo
{
public:
Foo(A a, B b) : m_a(std::move(a)), m_b(std::move(b)) { }
template <typename Arg>
auto operator()(Arg && arg) -> decltype(impl(std::forward<Arg>(arg), typename category<Arg>::type()))
{
return impl(std::forward<Arg>(arg), typename category<Arg>::type());
}
private:
template <typename Arg>
auto impl(Arg && arg, green_tag) -> decltype(m_a.green(std::forward<Arg>(arg)) + m_b.green(std::forward<Arg>(arg)))
{
return m_a.green(std::forward<Arg>(arg)) + m_b.green(std::forward<Arg>(arg));
}
template <typename Arg>
auto impl(Arg && arg, blue_tag) -> decltype(m_a.blue(std::forward<Arg>(arg)) + m_b.blue(std::forward<Arg>(arg)))
{
return m_a.blue(std::forward<Arg>(arg)) + m_b.blue(std::forward<Arg>(arg));
}
A m_a;
B m_b;
};
另一个版本可以使用辅助结构:
template <typename A, typename B, typename Arg, typename Category = typename category<Arg>::type>
struct Foo_Returns;
template <typename A, typename B, typename Arg>
struct Foo_Returns<A, B, Arg, green_tag>
{
typedef decltype(std::declval<A>().green(std::declval<Arg>()) +
std::declval<B>().green(std::declval<Arg>())) type;
type operator()(A & a, B & b, Arg && arg) const
{
return a.green(std::forward<Arg>(arg)) + b.green(std::forward<Arg>(arg));
}
};
template <typename A, typename B, typename Arg>
struct Foo_Returns<A, B, Arg, blue_tag>
{
typedef decltype(std::declval<A>().blue(std::declval<Arg>()) +
std::declval<B>().blue(std::declval<Arg>())) type;
type operator()(A & a, B & b, Arg && arg) const
{
return a.blue(std::forward<Arg>(arg)) + b.blue(std::forward<Arg>(arg));
}
};
template <typename A, typename B>
class Foo
{
public:
Foo(A a, B b) : m_a(std::move(a)), m_b(std::move(b)) { }
template <typename Arg>
typename Foo_Returns<A, B, Arg>::type
operator()(Arg && arg)
{
return Foo_Returns<A, B, Arg>()(m_a, m_b, std::forward<Arg>(arg));
}
private:
A m_a;
B m_b;
};
哪个版本更好?还有哪些其他可能的方法?
最佳答案
我会避免所有辅助类/结构。每个助手都需要编译器将其存储在某个地方并进行额外的查找。如果没有这些类,编译器至少有机会优化事物,但我无法想象辅助类可以改善您展示的示例中的情况。
对于您的绿色/蓝色示例,我什至会考虑使用 SFINAE 来缩短代码并减少实例化类/方法的数量:
template <typename A, typename B>
class Foo
{
public:
Foo(A a, B b) : m_a(std::move(a)), m_b(std::move(b)) { }
template <typename Arg>
auto operator()(const Arg & arg) ->
typename std::enable_if< is_green<Arg>::value,
decltype(m_a.green(arg) + m_b.green(arg) >::type
{
return m_a.green(arg) + m_b.green(arg);
}
template <typename Arg>
auto operator()(const Arg & arg) ->
typename std::enable_if< is_blue<Arg>::value,
decltype(m_a.blue(arg) + m_b.blue(arg)) >::type
{
return m_a.blue(arg) + m_b.blue(arg);
}
private:
A m_a;
B m_b;
};
我还认为这更易于维护,YMMV。对于编译时性能,一如既往,只有一个真正的建议:衡量它。
编辑: 我将参数从 Arg&&
更改为至 const Arg&
并删除了双 std::forward<Arg>(...)
因为这是非法的,请参阅评论。
关于c++ - 返回类型扣: What method is preferred?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15481425/
有没有办法可以清除 iPhone 应用程序的钥匙串(keychain)?清除命令或所有键的列表,以便我可以自己删除它们。 最佳答案 不存在清除命令之类的东西。 无论如何,由于您的应用程序可以访问的钥匙
我是一名优秀的程序员,十分优秀!