C++ 类模板专门化,接受const/volatile限定和&;vs&&;
我专门为我的类型C++ 类模板专门化,接受const/volatile限定和&;vs&&;,c++,templates,c++11,template-specialization,template-meta-programming,C++,Templates,C++11,Template Specialization,Template Meta Programming,我专门为我的类型std::common_type。我定义了以下专业化: common_type<my_type, my_type> 肯定有更好的办法吗?据我统计,如果我们忽略const&和const volatile&& 注意:my_类型实际上是一个类模板本身,因此specialize看起来更像 template<intmax_t lhs_min, intmax_t lhs_max, intmax_t rhs_min, intmax_t rhs_max> class c
std::common_type
。我定义了以下专业化:
common_type<my_type, my_type>
肯定有更好的办法吗?据我统计,如果我们忽略const&
和const volatile&&
注意:my_类型实际上是一个类模板本身,因此specialize看起来更像
template<intmax_t lhs_min, intmax_t lhs_max, intmax_t rhs_min, intmax_t rhs_max>
class common_type<my_type<lhs_min, lhs_max>, my_type<rhs_min, rhs_max>>
模板
类公共类型
其中结果为my\u type
如果我能够完全控制主模板定义,那么解决方案将非常简单,但我显然无法更改
std::common_type
我建议编写没有cv-和ref-限定符的专门化,
并在std::common_type
周围使用包装器,如下所示:
template <typename T>
using decay_t = typename std::decay<T>::type;
/* Our wrapper which passes decayed types to std::common_type<>. */
template <typename... T>
using CommonType = std::common_type<decay_t<T>...>;
namespace std {
/* Specialization for my_type<>. */
template <intmax_t lhs_min, intmax_t lhs_max,
intmax_t rhs_min, intmax_t rhs_max>
struct common_type<my_type<lhs_min, lhs_max>,
my_type<rhs_min, rhs_max>> {
using type = /* ... */;
};
} // std
template <typename Lhs, typename Rhs>
using common_type_impl_t =
decay_t<decltype(true ? std::declval<Lhs>() : std::declval<Rhs>())>;
很好用
我很困惑专业化是如何被使用的,直到我意识到它不是。std::common_type
的一般实现在if-else表达式上使用decltype()
,如下所示:
template <typename T>
using decay_t = typename std::decay<T>::type;
/* Our wrapper which passes decayed types to std::common_type<>. */
template <typename... T>
using CommonType = std::common_type<decay_t<T>...>;
namespace std {
/* Specialization for my_type<>. */
template <intmax_t lhs_min, intmax_t lhs_max,
intmax_t rhs_min, intmax_t rhs_max>
struct common_type<my_type<lhs_min, lhs_max>,
my_type<rhs_min, rhs_max>> {
using type = /* ... */;
};
} // std
template <typename Lhs, typename Rhs>
using common_type_impl_t =
decay_t<decltype(true ? std::declval<Lhs>() : std::declval<Rhs>())>;
过去了。现在,把volatile
扔进去,它就会像@Vincent指出的那样崩溃,这进一步证明了没有使用专门化
因此,我的结论是,两种情况中的一种会发生:
- 标准实现将发生变化,这样即使存在cv-和ref-限定符,也会使用专门化,在这种情况下,您可以丢弃
包装器,这很简单,而且您只定义了一个专门化CommonType
- 标准实现没有改变,但您仍然只定义了一个专门化,并使用
CommonType
通用类型的两侧。这允许将一方的专门化数量减少到12个。如果在my\u type
和my\u type
的专门化之间只需要一个公共类型,那么只需在一侧专门化就足够了。否则,您必须在右侧克隆它们,产生24个专门化
struct my_type;
struct unique_t;
#include <type_traits>
template<class L, class R, class = void>
struct mytype_common_type
{
// not many specializations are required here,
// as you can use std::decay and don't have to use "Exact Matches"
using type = unique_t;
};
namespace std
{
template<class T> struct common_type<my_type, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type const, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type volatile, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type const volatile, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type const&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type volatile&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type const volatile&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type&&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type const&&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type volatile&&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type const volatile&&, T>
: mytype_common_type<my_type, T> {};
}
template<class T>
using Decay = typename std::decay<T>::type;
int main()
{
static_assert(std::is_same<unique_t,
std::common_type<my_type const volatile&&, int>::type
>{}, "!");
}
struct my_type;
结构唯一性;
#包括
模板
结构mytype\u公共类型
{
//这里需要的专业不多,
//因为您可以使用std::decay,而不必使用“精确匹配”
使用类型=唯一\u t;
};
名称空间标准
{
模板结构公共类型
:mytype_common_type{};
模板结构公共类型
:mytype_common_type{};
模板结构公共类型
:mytype_common_type{};
模板结构公共类型
:mytype_common_type{};
模板结构公共类型
:mytype_common_type{};
模板结构公共类型
:mytype_common_type{};
模板结构公共类型
:mytype_common_type{};
模板结构公共类型
:mytype_common_type{};
模板结构公共类型
:mytype_common_type{};
模板结构公共类型
:mytype_common_type{};
模板结构公共类型
:mytype_common_type{};
模板结构公共类型
:mytype_common_type{};
}
模板
使用Decay=typename std::Decay::type;
int main()
{
静态断言(std::is_same{},“!”);
}
std::common_type
的标准库实现有哪些功能?这里的实现没有多少自由度。它必须调用std::decay
(或者有一个无法区分的实现)。毫无疑问,gcc 4.8.2就是这么做的,只是为了确保:您不能使用与std::common_type
不同的东西,即更改“呼叫站点”?您不能定义受SFINAE保护的转换运算符模板来“自然”执行my_type
?我可以强制所有用户在调用站点使用特殊的common_type
,但我正在尝试编写通用库。我不能指望我的所有用户(以及他们可能使用的所有库)总体上都使用我的特殊common_type
:这违背了泛型代码的目的。我不能定义转换运算符/隐式构造函数来完成这项工作,因为C++假设您想将其中一种类型转换为另一种类型。我的两个类的公共类型通常是第三种类型,不能由操作符处理:
。我认为您至少可以通过使用部分专门化而不是显式(完全)专门化,将问题减少到二进制公共类型
一侧的所有cv限定引用类型,类似于模板公共类型
然后检查删除引用后,T
是否是myu类型的专门化(通过继承重定向)。我猜chrono
之所以有效,是因为duration
s的隐式转换,而不是因为common\u类型的专门化。当然,这对OP不起作用(结果类型可能是第三种类型)。volatile
的东西不起作用,因为转换需要一个常量&
,而不是常量volatile&
。实际上,我不知道如何在右侧复制它。如果我定义std::common_type
和std::common_type
,这不会导致不明确的专门化吗?@DavidStone你是对的,如果你只是使用专门化common_type
和common_type
,那将是不明确的。但是,您可以通过对右侧的专门化使用enable\u if
来修复此问题:template struct common\u type:mytype\u common\u type{}代码>
struct my_type;
struct unique_t;
#include <type_traits>
template<class L, class R, class = void>
struct mytype_common_type
{
// not many specializations are required here,
// as you can use std::decay and don't have to use "Exact Matches"
using type = unique_t;
};
namespace std
{
template<class T> struct common_type<my_type, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type const, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type volatile, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type const volatile, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type const&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type volatile&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type const volatile&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type&&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type const&&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type volatile&&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type const volatile&&, T>
: mytype_common_type<my_type, T> {};
}
template<class T>
using Decay = typename std::decay<T>::type;
int main()
{
static_assert(std::is_same<unique_t,
std::common_type<my_type const volatile&&, int>::type
>{}, "!");
}