当前位置: 首页 > 知识库问答 >
问题:

专门化bool整数浮点返回类型的模板

蒋鸿文
2023-03-14

我想编写一个函数模板,它返回各种类型的随机变量(bool、char、short、int、float、double,以及这些变量的无符号版本)。

我看不出如何使用最新的C 11标准库来实现这一点,因为我需要使用统一的int分布或统一的real分布。我想我可以专门化模板:

template<typename T>
T randomPrimitive() { std::uniform_int_distribution<T> dst; std::mt19937 rng; return dst(rng); }

template<>
bool randomPrimitive<bool>() { std::uniform_int_distribution<signed char> dst; std::mt19937 rng; return dst(rng) >= 0 ? true : false; }

template<typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type randomPrimitive() { std::uniform_real_distribution<T> dst; std::mt19937 rng; return dst(rng); }

在Visual Studio 2012 Update 3下,这给出了:

错误C2668:“‘匿名命名空间’::randomPrimitive”:对重载函数的调用不明确

当我尝试编译时:

randomPrimitive<float>();

有没有办法专门化函数模板,这样我就可以为bool、其他整数类型和浮点类型编写三种不同的实现?

共有3个答案

上官飞
2023-03-14

您不特化(完全特化除外),您会重载函数模板。重载只适用于参数类型,而不适用于结果类型。由于你的函数模板不接受任何参数,因此重载解决方案无法决定为你选择什么。

在这种情况下,您必须指定模板参数,或者尝试使用转换运算符:

struct RandomPrimitive
{
    operator float()
    {
        // your float implementation here
    }

    operator int()
    {
        // your int implementation here
    }

    // more operator type() as needed
};

RandomPrimitive randomPrimitive;

float f = randomPrimitive;
int i = randomPrimitive;
宰父君昊
2023-03-14

模板专门化的语法不正确。请尝试以下方法:

template<>
bool randomPrimitive<bool>()
{
    std::uniform_int_distribution<signed char> dst;
    std::mt19937 rng;
    return dst(rng) >= 0;
}

区别在于

类型char可以是unsigned charsigned char——这取决于编译器。您的实现显然依赖于将char解释为signed char,因此您应该明确这一点。

还有,表达式x?true:false其中x是一个bool表达式,与简单的x相同。

柳绪
2023-03-14

你的编辑越来越接近了。您需要将您的“积分”版本限制为积分类型。这将消除模糊性:

template<typename T>
typename std::enable_if
<
    std::is_integral<T>::value,
    T
>::type
randomPrimitive()

但如果您现在使用以下内容运行它:

#include <iostream>

int
main()
{
    for (int i = 0; i < 10; ++i)
        std::cout << randomPrimitive<float>() << '\n';
    for (int i = 0; i < 10; ++i)
        std::cout << randomPrimitive<double>() << '\n';
    for (int i = 0; i < 10; ++i)
        std::cout << (int)randomPrimitive<signed char>() << '\n';
    for (int i = 0; i < 10; ++i)
        std::cout << randomPrimitive<unsigned>() << '\n';
    for (int i = 0; i < 10; ++i)
        std::cout << randomPrimitive<bool>() << '\n';
}

您将得到如下结果:

0.814724
0.814724
0.814724
0.814724
0.814724
0.814724
0.814724
0.814724
0.814724
0.814724
0.135477
0.135477
0.135477
0.135477
0.135477
0.135477
0.135477
0.135477
0.135477
0.135477
92
92
92
92
92
92
92
92
92
92
3499211612
3499211612
3499211612
3499211612
3499211612
3499211612
3499211612
3499211612
3499211612
3499211612
1
1
1
1
1
1
1
1
1
1

到达那里,但不完全是随机的。问题是你每次使用都在构建一个新的引擎。您想要的是创建一次URNG,然后继续从中获得随机位:

std::mt19937&
get_eng()
{
    static std::mt19937 eng;
    return eng;
}

你也应该只创建一次发行版。他们大多数是无国籍的,但不是所有人。最好假设它们都带有状态,而你不想把状态扔掉。

static std::uniform_real_distribution<T> dst;

这将大大改善情况,但您还没有做到:

0.814724
0.135477
0.905792
0.835009
0.126987
0.968868
0.913376
0.221034
0.632359
0.308167
0.547221
0.188382
0.992881
0.996461
0.967695
0.725839
0.98111
0.109862
0.798106
0.297029
92
13
49
122
46
7
105
45
43
8
2816384844
3427077306
153380495
1551745920
3646982597
910208076
4011470445
2926416934
2915145307
1712568902
0
1
1
1
1
0
1
0
1
0

我注意到,signed char中的所有10个值都是正值。这看起来不对。原来std::uniform\u int\u distribution有一个如下所示的构造函数:

explicit uniform_int_distribution(IntType a = 0,
                                  IntType b = numeric_limits<IntType>::max());

我猜这不是你想要的,所以:

static std::uniform_int_distribution<T> dst(std::numeric_limits<T>::min(), 
                                            std::numeric_limits<T>::max());

最后,如果您想要一个随机的bool,请使用std::bernoulli\u分布。

把这一切放在一起:

#include <random>

std::mt19937&
get_eng()
{
    static std::mt19937 eng;
    return eng;
}

template<typename T>
typename std::enable_if
<
    std::is_integral<T>::value,
    T
>::type
randomPrimitive()
{
    static std::uniform_int_distribution<T> dst(std::numeric_limits<T>::min(), 
                                                std::numeric_limits<T>::max());
    return dst(get_eng());
}

template<>
bool
randomPrimitive<bool>()
{
    static std::bernoulli_distribution dst;
    return dst(get_eng());
}

template<typename T>
typename std::enable_if
<
    std::is_floating_point<T>::value,
    T
>::type
randomPrimitive()
{
    static std::uniform_real_distribution<T> dst;
    return dst(get_eng());
}

#include <iostream>

int
main()
{
    for (int i = 0; i < 10; ++i)
        std::cout << randomPrimitive<float>() << '\n';
    for (int i = 0; i < 10; ++i)
        std::cout << randomPrimitive<double>() << '\n';
    for (int i = 0; i < 10; ++i)
        std::cout << (int)randomPrimitive<signed char>() << '\n';
    for (int i = 0; i < 10; ++i)
        std::cout << randomPrimitive<unsigned>() << '\n';
    for (int i = 0; i < 10; ++i)
        std::cout << randomPrimitive<bool>() << '\n';
}

这对我来说是:

0.814724
0.135477
0.905792
0.835009
0.126987
0.968868
0.913376
0.221034
0.632359
0.308167
0.547221
0.188382
0.992881
0.996461
0.967695
0.725839
0.98111
0.109862
0.798106
0.297029
92
13
-79
-6
46
-121
-23
45
43
8
2816384844
3427077306
153380495
1551745920
3646982597
910208076
4011470445
2926416934
2915145307
1712568902
0
1
1
1
1
0
1
0
1
0

如果这仍然没有输出你想要的,希望你有足够的方向从这里开始。

 类似资料:
  • 在C 11中,如何专门化一个函数模板,该模板使用decltype声明为“复杂”的尾部返回类型?以下内容适用于GCC,但在VC2013中产生了“错误C2912:显式专业化‘int f(void)’i不是功能模板的专业化”: 我说“复杂”是因为缺乏一个技术上精确的词,因为我不确定是什么造成了差异。例如,以下decltype使用不依赖于任何函数结果类型的内置操作,可以与模板专业化配合使用: 自动f()-

  • 我有一些代码使用两种不同类型的颜色,每个通道8位和每个通道16位,每个都由一个结构表示。为了有效地重用我的代码,我有一个模板函数可以对它们进行一些渲染。因此,我希望有一个模板函数来获取我的颜色通道的最大值。 我最初的尝试是这样的。我只展示了8 bpc的专业化 这不会在Visual studio 2012中编译。我明白了 1个 对我来说,我觉得这应该行得通,但我一直找不到任何例子。在Speciali

  • 我试图调用一个模板类成员函数专门化,它从类的构造函数中返回一个值,但我似乎找不到正确的语法(如果存在的话)。下面是我的代码,下面是来自编译器(而不是链接器)的错误消息。 错误消息:g++-std=c++11-o t1 t1.cpp t1.cpp:19:18:错误:在'constexpr'模板constexpr const char*name()之前需要'<';^T1.CPP:22:26:错误:“c

  • 我有一个通用算法,需要访问其模板类型的特征。有一个特征类可以专门用于提供这些特征。 在我的类中使用此算法时,我想将其与类中定义的私有类型一起使用。 然而,专门化只能发生在或全局范围内,而我的类是不可访问的。 是否有可能以某种方式专门化具有私有类型的模板,至少在可访问此类型的范围内? 也许可以将这个专门化声明为一个类?

  • 考虑代码: 我用不同的编译器(通过编译器资源管理器)测试了代码。 如果Clang 7.0.0编译,而给出错误: :8:20:错误:没有与函数模板专用化“栏”匹配的函数模板 :7:26:注意:已忽略候选模板:无法将'void()'与'int()'匹配 Visual C同意(MSVC 19 2017 RTW): (8) :错误C2912:显式专门化“int Test::bar(void)”不是函数模板

  • 也许我累了,但是我被这个简单的局部特化卡住了,它不起作用,因为指定模板参数: 将替换为,或没有帮助。那么这种专门化是否可能呢?