我是SFINAE的新手。我有一个模板,我希望能够接受可以简单地调用sizeof(x)来确定大小的类,或者如果值是动态的,则需要x.size()。
我试图围绕这样看起来如何平滑,我认为界面:size_t size(const Item& item)
似乎已经足够好了。
以下是一个有效的示例:
#include <iostream>
#include <cstdio>
#include <type_traits>
template <typename T>
class Fixed {
public:
typedef T Item;
static const bool kFixedSize = true;
static size_t size() {
return sizeof(T);
}
};
template <typename T>
class Dynamic {
public:
typedef T Item;
static const bool kFixedSize = false;
static size_t size(const T& item) {
return item.size();
}
};
template <typename T>
class Serialize {
public:
template <typename = typename std::enable_if<T::kFixedSize> >
size_t size(typename T::Item&) {
return T::size();
}
template <typename = typename std::enable_if<!T::kFixedSize> >
size_t size(const typename T::Item& item) {
return T::size(item);
}
};
int main() {
Serialize< Fixed<int> > fixed;
int a = 0;
std::cout << fixed.size(a) << std::endl;
Serialize< Dynamic<std::string> > dynamic;
std::cout << dynamic.size("string") << std::endl;
return 0;
}
它有一个问题,虽然一个是:size_t size(typename T::Item&)
而另一个是size_t size(const typename T::Item& item)
,否则我正在重载模板的编译器合规性。第二个看起来似乎太匹配非常棘手的代码来实现目标 - 有更好的方法来做到这一点吗?
答案 0 :(得分:0)
我相信你想要这样的东西
//class hierarchy to set the priority for type matching
struct second_priority
{
};
struct first_priority : public second_priority
{};
template<typename T>
auto size_impl(T const & data, second_priority t) -> int
{
return sizeof(data);
}
template<typename T>
auto size_impl(T const & data , first_priority t) -> decltype(data.size(),int())
{
return data.size();
}
template<typename T>
int size(T const & data )
{
return size_impl(data,first_priority{});
}
答案 1 :(得分:0)
我认为@Gautam Jha使用SFINAE提出了一个很好的解决方案。你可以通过在'else'的情况下使用省略号来缩短它,所以你不需要使用这个辅助类,它的继承:
template<typename T>
auto size_impl(T const & item, int) -> decltype(item.size())
{
return item.size();
}
template<typename T>
auto size_impl(T const & item, ...) -> size_t
{
return sizeof(T);
}
template<typename T>
auto size(T const & item) -> size_t
{
return size_impl(item, 0);
}
你玩SFINAE很酷,但通常有更简单(即阅读和理解)的方法来实现相同的目标,请参阅POW的解决方案(不幸的是已被删除)。
答案 2 :(得分:0)
由于你要做的就是调用不同的函数来获得Dynamic
或Fixed
的大小,你可以用不同的方式实现这些类,并在Serialize中使用它们:
#include <iostream>
#include <cstdio>
#include <type_traits>
template <typename T>
class Fixed {
public:
typedef T Item;
static size_t size(const T&) {
return sizeof(T);
}
};
template <typename T>
class Dynamic {
public:
typedef T Item;
static size_t size(const T& item) {
return item.size();
}
};
template <typename T>
class Serialize {
public:
size_t size(typename T::Item const& x) {
return T::size(x);
}
};
int main() {
Serialize< Fixed<int> > fixed;
int a = 0;
std::cout << fixed.size(a) << std::endl;
Serialize< Dynamic<std::string> > dynamic;
std::cout << dynamic.size( std::string{"string"} ) << std::endl;
return 0;
}
但是,我会考虑使用类型特征或自由函数来做同样的事情。这将是更具可扩展性的,因为您必须为新类型提供新特征或重载,例如一些只有长度法的容器。
#include <iostream>
#include <cstdio>
#include <type_traits>
size_t size(int) {return sizeof(int);}
size_t size(std::string const& s) {return s.size();}
template<typename T>
struct size_trait
{
};
template<>
struct size_trait<int>
{
static size_t size(int) {return sizeof(int);}
};
template<>
struct size_trait<std::string>
{
static size_t size(std::string const& x) {return x.size();}
};
template <typename T>
class Serialize {
public:
size_t size(T const& x) {
return ::size(x);
}
size_t size_(T const& x) {
return size_trait<T>::size(x);
}
};
int main() {
Serialize< int > fixed;
int a = 0;
std::cout << fixed.size(a) << std::endl;
std::cout << fixed.size_(a) << std::endl;
Serialize< std::string > dynamic;
std::cout << dynamic.size( std::string{"string"} ) << std::endl;
std::cout << dynamic.size_( std::string{"string"} ) << std::endl;
return 0;
}