草庐IT

c++ - 出现在可变模板参数包的任何位置的类型的类模板的部分特化

coder 2023-11-17 原文

我已经定义了一个作为整数的类型。我想为我的类型定义 std::common_type 的特化。然而,这个特化应该能够给出 bounded_integer (我的类)的 common_type 与任意数量的其他 bounded_integer 或内置整数类型的参数的组合。我希望以下代码全部有效:

std::common_type<bounded_integer<1, 10>>::type
std::common_type<bounded_integer<1, 10>, int>::type
std::common_type<int, long, bounded_integer<1, 10>>::type
std::common_type<int, int, long, short, long long, short, bounded_integer<1, 10>, int, short, short, short, ..., short, bounded_integer<1, 10>>::type

我第一次尝试解决这个问题是使用 enable_if。然而,我意识到这不允许我与 common_type 的库定义区分开来,因为我所拥有的本质上是

#include <type_traits>

class C {};

template<typename T, typename... Ts>
class contains_c {
public:
        static constexpr bool value = contains_c<T>::value or contains_c<Ts...>::value;
};
template<typename T>
class contains_c<T> {
public:
        static constexpr bool value = std::is_same<T, C>::value;
};

namespace std {

template<typename... Args, typename std::enable_if<contains_c<Args...>::value>::type>
class common_type<Args...> {
public:
        using type = C;
};

}       // namespace std

int main() {
}

“部分特化”实际上只是“任何参数”,它并不比我们拥有的更专业。

所以看起来唯一的解决方案是要求我的用户执行以下操作之一:

  1. 始终将 bounded_integer 作为 common_type 的第一个参数
  2. 始终使用我的 make_bounded(内置整数值)函数将它们的整数转换为 bounded_integer(因此不要将 common_type 专门用于内置类型与 bounded_integer 的组合)
  3. 永远不要将 bounded_integer 放在大于 N 的位置,其中 N 是我确定的某个数字,类似于 Visual Studio 的旧可变参数模板解决方法

3 看起来像这样:

// all_bounded_integer_or_integral and all_are_integral defined elsewhere with obvious definitions
template<intmax_t minimum, intmax_t maximum, typename... Ts, typename = type std::enable_if<all_bounded_integer_or_integral<Ts...>::value>::type>
class common_type<bounded_integer<minimum, maximum>, Ts...> {
};
template<typename T1, intmax_t minimum, intmax_t maximum, typename... Ts, typename = typename std::enable_if<all_are_integral<T1>::value>::type, typename = typename std::enable_if<all_bounded_integer_or_builtin<Ts...>::value>::type>
class common_type<T1, bounded_integer<minimum, maximum>, Ts...> {
};
template<typename T1, typename T2, intmax_t minimum, intmax_t maximum, typename... Ts, typename = typename std::enable_if<all_are_integral<T1, T2>::value>::type, typename = typename std::enable_if<all_bounded_integer_or_builtin<Ts...>::value>::type>
class common_type<T1, T2, bounded_integer<minimum, maximum>, Ts...> {
};
// etc.

对于我无法更改其原始定义的类,是否有更好的方法来实现此目的(当所有类型都满足一个条件并且任何类型都满足另一个条件时的模板特化)?

编辑:

根据答案,我的问题还不够清楚。

首先,预期行为:

如果有人调用 std::common_type 并且所有类型都是 bounded_integer 的实例或内置数字类型,我希望结果是一个 bounded_integer,它具有所有可能的最小值中的最小值和最大值所有可能的最大值。

问题:

当有人对任意数量的 bounded_integer 调用 std::common_type 时,我有一个可行的解决方案。但是,如果我只特化两个参数的版本,那么我会遇到以下问题:

std::common_type<int, unsigned, bounded_integer<0, std::numeric_limits<unsigned>::max() + 1>

应该给我

bounded_integer<std::numeric_limits<int>::min(), std::numeric_limits<unsigned>::max() + 1>

然而,事实并非如此。它首先将 common_type 应用于 intunsigned ,它遵循标准积分提升规则,给出 unsigned .然后它返回 common_type 的结果与 unsigned和我的 bounded_integer , 给予

bounded_integer<0, std::numeric_limits<unsigned>::max() + 1>

所以通过添加 unsigned到参数包的中间,即使它对结果类型绝对没有影响(它的范围完全包含在所有其他类型的范围内),它仍然会影响结果。我能想到的防止这种情况的唯一方法是专门化 std::common_type对于任意数量的内置整数,后跟 bounded_integer , 后跟任意数量的内置整数或 bounded_integer .

我的问题是:我怎样才能做到这一点而不必通过手动写出任意数量的参数后跟一个 bounded_integer 来近似它?后跟一个参数包,或者这是不可能的?

编辑 2:

common_type 会给出错误值的原因可以用这个遵循标准的推理来解释(引用自 N3337)

common_typeintunsignedunsigned .例如:http://ideone.com/9IxKIW .标准语可在§ 20.9.7.6/3 中找到,其中 common_type两个值的是

typedef decltype(true ? declval<T>() : declval<U>()) type;

在 § 5.16/6 中,它说

The second and third operands have arithmetic or enumeration type; the usual arithmetic conversions are performed to bring them to a common type, and the result is of that type.

通常的算术转换在 § 5/9 中定义为

Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type shall be converted to the type of the operand with unsigned integer type.

最佳答案

std::common_type 将其自身的双参数特化外推到 n 参数情况。您只需要专门化两个参数的情况。

template< typename other, int low, int high >
struct common_type< other, ::my::ranged_integer< low, high > > {
    using type = other;
};

template< typename other, int low, int high >
struct common_type< ::my::ranged_integer< low, high >, other > {
    using type = other;
};

template< int low, int high >
struct common_type< ::my::ranged_integer< low, high >,
                    ::my::ranged_integer< low, high > > {
    using type = ::my::ranged_integer< low, high >;
};

这使得不同范围整数之间的 common_type 未定义。我想您可以使用 minmax 来完成。

如果你的类支持继承,你也可以制作一个is_ranged_integer trait。

不要忘记将您的库放在命名空间中。

关于c++ - 出现在可变模板参数包的任何位置的类型的类模板的部分特化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18679093/

有关c++ - 出现在可变模板参数包的任何位置的类型的类模板的部分特化的更多相关文章

  1. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  2. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  3. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  4. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  5. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  6. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

  7. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  8. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  9. ruby-on-rails - 在默认方法参数中使用 .reverse_merge 或 .merge - 2

    两者都可以defsetup(options={})options.reverse_merge:size=>25,:velocity=>10end和defsetup(options={}){:size=>25,:velocity=>10}.merge(options)end在方法的参数中分配默认值。问题是:哪个更好?您更愿意使用哪一个?在性能、代码可读性或其他方面有什么不同吗?编辑:我无意中添加了bang(!)...并不是要询问nobang方法与bang方法之间的区别 最佳答案 我倾向于使用reverse_merge方法:option

  10. ruby-on-rails - link_to 不显示任何 rails - 2

    我试图在索引页中创建一个超链接,但它没有显示,也没有给出任何错误。这是我的index.html.erb代码。ListingarticlesTitleTextssss我检查了我的路线,我认为它们也没有问题。PrefixVerbURIPatternController#Actionwelcome_indexGET/welcome/index(.:format)welcome#indexarticlesGET/articles(.:format)articles#indexPOST/articles(.:format)articles#createnew_articleGET/article

随机推荐