Mor*_*hai 15 c++ mfc templates c++17
我需要一个简单的方法来获取类的对象的数量/长度/大小T这里T是某种集合类型,如中std::map,std::list,std::vector,CStringArray,CString,std::string,...
对于大多数标准类型,T::size()是正确答案,因为大多数MFC类T::GetSize()是正确的,因为CString它是T::GetLength().
我希望有一个像:
template <typename T> auto size(const T & t)
Run Code Online (Sandbox Code Playgroud)
...评估正确的成员函数调用.
看起来应该有一种简单的方法来调用一个traits模板,在T该模板上有一个size(const T & t)成员,它本身使用SFINAE存在或不存在,如果它存在,那么根据定义调用一个适当的方法t.size_function()来返回元素的数量.那个例子T.
我可以编写一个精心设计的has_member类型 - 特征模板 - 在stackoverflow上有一些例子 - 所有这些都让我觉得很复杂"必须有一个更简单的方法".使用C++ 17,似乎应该轻松优雅地解决这个问题?
这里和这里的这些讨论似乎使用了一个不优雅的解决方案,其中一些答案使用预处理器宏来完成工作.这还有必要吗?
但是......当然,必须有一种方法可以使用这样一个事实,即在a上调用正确的成员函数T是可编译的,并且调用错误的函数无法编译 - 不能直接用于创建正确的类型特征包装器给定的类型T?
我想要的是:
template <typename T>
auto size(const T & collection)
{
return collection_traits<T>::count(collection);
}
Run Code Online (Sandbox Code Playgroud)
collection_traits<T>选择精确的特化是因为它是唯一适合的T(即它调用正确的实例方法).
Vit*_*meo 31
您可以使用表达式SFINAE和多个重载.
这个想法如下:检查if是否x.size()是您的类型的有效表达式 - 如果是,则调用并返回它.重复.getSize和.getLength.
鉴于:
struct A { int size() const { return 42; } };
struct B { int getSize() const { return 42; } };
struct C { int GetLength() const { return 42; } };
Run Code Online (Sandbox Code Playgroud)
你可以提供:
template <typename T>
auto size(const T& x) -> decltype(x.size()) { return x.size(); }
template <typename T>
auto size(const T& x) -> decltype(x.getSize()) { return x.getSize(); }
template <typename T>
auto size(const T& x) -> decltype(x.GetLength()) { return x.GetLength(); }
Run Code Online (Sandbox Code Playgroud)
用法:
int main()
{
size(A{});
size(B{});
size(C{});
}
Run Code Online (Sandbox Code Playgroud)
该解决方案易于扩展,可与模板化的容器无缝协作.
如果一个类型暴露两个吸气剂怎么办?
上面的解决方案会导致歧义,但通过引入解决这个问题的排名/排序很容易解决.
首先,我们可以创建一个rank允许我们任意优先级重载的类:
template <int N> struct rank : rank<N - 1> { };
template <> struct rank<0> { };
Run Code Online (Sandbox Code Playgroud)
rank<N>可以隐式转换为rank<N - 1>.在重载决策期间,精确匹配优于转换链.
然后我们可以创建一个size_impl重载层次结构:
template <typename T>
auto size_impl(const T& x, rank<2>)
-> decltype(x.size()) { return x.size(); }
template <typename T>
auto size_impl(const T& x, rank<1>)
-> decltype(x.getSize()) { return x.getSize(); }
template <typename T>
auto size_impl(const T& x, rank<0>)
-> decltype(x.GetLength()) { return x.GetLength(); }
Run Code Online (Sandbox Code Playgroud)
最后,我们提供了一个接口函数,开始向正确的size_impl重载发送:
template <typename T>
auto size(const T& x) -> decltype(size_impl(x, rank<2>{}))
{
return size_impl(x, rank<2>{});
}
Run Code Online (Sandbox Code Playgroud)
使用类似D下面的类型
struct D
{
int size() const { return 42; }
int getSize() const { return 42; }
int GetLength() const { return 42; }
};
Run Code Online (Sandbox Code Playgroud)
现在将选择rank<2>超载size_impl:
最简单的解决方案IMO是函数重载.
// Default implementation for std containers.
template <typename Container>
std::size_t size(Container const& c) { return c.size(); }
// Overloads for others.
std::size_t size(CStringArray const& c) { return c.GetSize(); }
std::size_t size(CString const& c) { return c.GetLength(); }
// ... etc.
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1254 次 |
| 最近记录: |