Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 通过模板参数和constexpr语义在编译时生成浮点限制:_C++_Templates_Floating Point_C++17_Compile Time Constant - Fatal编程技术网

C++ 通过模板参数和constexpr语义在编译时生成浮点限制:

C++ 通过模板参数和constexpr语义在编译时生成浮点限制:,c++,templates,floating-point,c++17,compile-time-constant,C++,Templates,Floating Point,C++17,Compile Time Constant,我正在上一系列的课。我的函数类将接受一个函子类,该类存储一个指向某个已定义函数的函数指针,该函数具有一个从函数指针调用函数调用的运算符。它使用一个Limit类,该类当前将作为其上限和下限。它只有static constexpr函数返回边界并计算这些边界之间的元素数。如果下界=1,上界=5,则将为该函数计算的元素数生成5 以下是我对这些课程所做的: 首先我声明一个函数,比如f(x)=x,f(x)=x^2,或者f(x)=cos(x),等等 然后,我基于上述函数参数类型,为返回及其参数参数类型实例化

我正在上一系列的课。我的
函数
类将接受一个
函子
类,该类存储一个指向某个已定义函数的
函数指针
,该函数具有一个从函数指针调用函数调用的运算符。它使用一个
Limit
类,该类当前将
作为其上限和下限。它只有
static constexpr
函数返回边界并计算这些边界之间的元素数。如果下界=1,上界=5,则将为该函数计算的元素数生成5

以下是我对这些课程所做的:

  • 首先我声明一个函数,比如f(x)=x,f(x)=x^2,或者f(x)=cos(x),等等
  • 然后,我基于上述函数参数类型,为返回及其参数参数类型实例化一个
    Functor
    对象
  • 接下来,我将函数分配给我的
    Functor
    类的成员变量
  • 然后我实例化一个
    函数
    对象,给它提供函数范围的
    数据类型
    下限
    上限
  • 构建后的
    函数
    类自动从
    [上下]
    生成该函数的数据点,并将生成的值存储在其内部数组中
  • 函数
    类还包含一个
    操作符
    ,该操作符允许用户从任何给定输入中获取任何值
伪示例:

f(x) = x^2;

Functor<T,T> functor;
functor.member = &f(x);
Function<T,Lower,Upper,T> function(functor); 

// If T=int, Lower = -4, and Upper = 4 then the internal data set will be 
// (-4,16) (-3,9), (-2,4), (-1,1), (0,0), (1,1), (2,4), (3,9), (4,16)
// The user can also use it's operator to call function(9) and it will return 81

现在我要问的问题是,这将成为棘手的部分

我的代码目前是这样的,只要我的边界
[-a,b]
整数类型,一切都很好

让我们假设在我的最后一个例子中,例如使用
cos
,如果我想从
[-2pi,2pi]
得到我的边界,其中下限和上限都是浮点类型

问题:

f(x) = x^2;

Functor<T,T> functor;
functor.member = &f(x);
Function<T,Lower,Upper,T> function(functor); 

// If T=int, Lower = -4, and Upper = 4 then the internal data set will be 
// (-4,16) (-3,9), (-2,4), (-1,1), (0,0), (1,1), (2,4), (3,9), (4,16)
// The user can also use it's operator to call function(9) and it will return 81

目前在C++中,这是非标准的,大多数情况下编译不成:

template<float val> // or template<double>
struct foo() {
    constexpr float operator()() {
        return val;
    }
};
模板//或模板
结构foo(){
constexpr浮点运算符(){
返回val;
}
};
上述情况阻止我做类似的事情:

constexpr double PI{ 6.28318531 };

pipes::Functor<double, double> functor3;
functor3.FuncPtr = &cosine;
pipes::Function<double, -PI, PI, double> func3(functor3);
auto data3{ func3.data() };
for (auto& p : data3)
    std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func3(25) << "\n\n";   
template<typename T, T const &lower, T const &upper>
void foo() {
    std::cout << lower << " " << upper << std::endl;
}
constexpr-double-PI{6.28318531};
管道::函子函子3;
functor3.FuncPtr=&余弦;
管道::函数func3(functor3);
自动数据3{func3.data()};
用于(自动&p:data3)

STD::Cuth

在现代C++中,以及模板是如何设计的,我不得不稍微重构我的代码。这迫使我不得不使用

std::vector
而不是
std::array
,因为我们不能使用
浮点类型作为常量模板参数。。。所以我不得不换了两门课。。。我必须更改我的
限制
类和
函数

我的
限制
类现在接受
类型
而不是
常量积分类型
,它存储3个成员变量。它还有一个默认构造函数和一个用户构造函数。这些函数现在只是
constexpr
,而不是静态的

我的
函数
类现在存储
限制
类对象,并且
数据点
不再像现在的
std::vector那样是
std::array
。它的构造函数现在也接受
限制
对象

我还考虑了
浮点
范围的
步长
大小

下面是我修改过的代码在给定输出时的样子:

main.cpp

#include <cmath>
#include <exception>
#include <iostream>

#include "Function.h"

int main() {
    try {
        pipes::Functor<int, int> functor1;
        functor1.FuncPtr = &square;
        pipes::Function<int, -10, 10, int> func1( functor1 );
        auto data1{ func1.data() };
        for (auto& p : data1)
            std::cout << '(' << p.first << ',' << p.second << ")\n";
        std::cout << '\n';
        std::cout << "f(25) = " << func1(25) << "\n\n";

        pipes::Functor<int, int> functor2;
        functor2.FuncPtr = &linear;
        pipes::Function<int, -10, 10, int> func2(functor2);
        auto data2{ func2.data() };
        for (auto& p : data2)
            std::cout << '(' << p.first << ',' << p.second << ")\n";
        std::cout << '\n';
        std::cout << "f(25) = " << func2(25) << "\n\n";

        pipes::Functor<double, double> functor3;
        functor3.FuncPtr = &cosine;
        pipes::Function<double, -7, 7, double> func3(functor3);
        auto data3{ func3.data() };
        for (auto& p : data3)
            std::cout << '(' << p.first << ',' << p.second << ")\n";
        std::cout << '\n';
        std::cout << "f(25) = " << func3(25) << "\n\n";

    }
    catch (const std::exception& e) {
        std::cerr << e.what() << "\n\n";
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}
#include <cmath>
#include <iostream>
#include <exception>

#include "Function.h"

constexpr int square(int x) {
    return x * x;
}

constexpr int linear(int x) {
    return x;
}

double cosine(double x) {
    return cos(x);
}

//template<float val>
struct foo {
    float operator()(float val) { return val; }
};

int main() {
    try {
        pipes::Functor<int, int> functor1;
        pipes::Limits<int> limit1(-10, 10, 1);
        functor1.FuncPtr = &square;
        pipes::Function<int, int, int> func1( limit1, functor1 );
        auto data1{ func1.data() };
        for (auto& p : data1)
            std::cout << '(' << p.first << ',' << p.second << ")\n";
        std::cout << '\n';
        std::cout << "f(25) = " << func1(25) << "\n\n";

        pipes::Functor<int,int> functor2;
        pipes::Limits<int> limit2(-10, 10, 1);
        functor2.FuncPtr = &linear;
        pipes::Function<int, int, int> func2(limit2, functor2);
        auto data2{ func2.data() };
        for (auto& p : data2)
            std::cout << '(' << p.first << ',' << p.second << ")\n";
        std::cout << '\n';
        std::cout << "f(25) = " << func2(25) << "\n\n";

        constexpr double PI{ 6.28318531 };

        pipes::Functor<double, double> functor3;
        pipes::Limits<double> limits3( (-PI), PI, 0.1);
        functor3.FuncPtr = &cosine;
        pipes::Function<double, double, double> func3(limits3, functor3);
        auto data3{ func3.data() };
        for (auto& p : data3)
            std::cout << '(' << p.first << ',' << p.second << ")\n";
        std::cout << '\n';
        std::cout << "f(25) = " << func3(25) << "\n\n";

    }
    catch (const std::exception& e) {
        std::cerr << e.what() << "\n\n";
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

这给了我想要的行为,然而,我试图用
数组
做同样的事情。。。我一直在猜测,直到
C++
支持
浮点常量
作为模板参数,我将不得不使用堆分配来解决
std::vector
,而不是
std::array
和堆栈缓存友好型容器…

我认为最接近您的构造是:

#include <iostream>
#include <array>

constexpr const double PI_2{ 6.28318531 };

template<double const &lower, double const &upper>
void foo() {
    static_assert(lower<upper, "invalid lower and upper value");
    
    constexpr size_t size = (upper-lower);
    std::array<int, size> test;
    
    std::cout << lower << " " << upper << " " << test.size() << std::endl;
}

template<double const &V>
struct neg {
  static constexpr double value = -V;
};

int main()
{
    foo<neg<PI_2>::value, PI_2>();
    
    return 0;
}
#包括
#包括
constexpr const double PI_2{6.28318531};
模板
void foo(){

static_assert(lowercurrency,仅当您为每个浮点范围指定自己的类型,如
struct pi_range{constexpr double lower=-IP,constexpr double upper=IP};
(或分别为每个下限和上限指定一个类型)时,它才会起作用使用
pi_range
like作为参数:
pipes::Function
@t.niese我有点理解您的意思,但是,我不想为不同的范围显式创建多个结构,我想能够“概括”它!使用
consteval
可能是可能的,但我还没有检查它(特别是因为它是c++20)但是,只要在某种程度上需要该值来标识模板,就不可能。因此,即使是
pipes::Function
也不起作用,因为其中的参数
-1.0
1.0
是模板标识的一部分。您不需要为该范围使用struct,您也可以只使用单个参数下半部分和上半部分的结构。@t.niese我现在正在尝试一些替代方法,但是,它迫使我使用
std::vector
,而不是
std::array
。我试图使用
array
使小样本大小对堆栈和缓存友好,但必须提前知道大小才是关键g这很难。使用
向量
,我不需要知道它的大小,可以在
函数
的构造函数中计算,我有一个工作示例,但是
浮点函数
f(x)
部分的
x
没有给我正确的值。这可能是由于
(-10,100)
(-9,81)
(-8,64)
(-7,49)
(-6,36)
(-5,25)
(-4,16)
(-3,9)
(-2,4)
(-1,1)
(0,0)
(1,1)
(2,4)
(3,9)
(4,16)
(5,25)
(6,36)
(7,49)
(8,64)
(9,81)
(10,100)

f(25) = 625

(-10,-10)
(-9,-9)
(-8,-8)
(-7,-7)
(-6,-6)
(-5,-5)
(-4,-4)
(-3,-3)
(-2,-2)
(-1,-1)
(0,0)
(1,1)
(2,2)
(3,3)
(4,4)
(5,5)
(6,6)
(7,7)
(8,8)
(9,9)
(10,10)

f(25) = 25

(-6.28319,1)
(-6.18319,0.995004)
(-6.08319,0.980067)
(-5.98319,0.955336)
(-5.88319,0.921061)
(-5.78319,0.877583)
(-5.68319,0.825336)
(-5.58319,0.764842)
(-5.48319,0.696707)
(-5.38319,0.62161)
(-5.28319,0.540302)
(-5.18319,0.453596)
(-5.08319,0.362358)
(-4.98319,0.267499)
(-4.88319,0.169967)
(-4.78319,0.0707372)
(-4.68319,-0.0291995)
(-4.58319,-0.128844)
(-4.48319,-0.227202)
(-4.38319,-0.32329)
(-4.28319,-0.416147)
(-4.18319,-0.504846)
(-4.08319,-0.588501)
(-3.98319,-0.666276)
(-3.88319,-0.737394)
(-3.78319,-0.801144)
(-3.68319,-0.856889)
(-3.58319,-0.904072)
(-3.48319,-0.942222)
(-3.38319,-0.970958)
(-3.28319,-0.989992)
(-3.18319,-0.999135)
(-3.08319,-0.998295)
(-2.98319,-0.98748)
(-2.88319,-0.966798)
(-2.78319,-0.936457)
(-2.68319,-0.896758)
(-2.58319,-0.8481)
(-2.48319,-0.790968)
(-2.38319,-0.725932)
(-2.28319,-0.653644)
(-2.18319,-0.574824)
(-2.08319,-0.490261)
(-1.98319,-0.400799)
(-1.88319,-0.307333)
(-1.78319,-0.210796)
(-1.68319,-0.112153)
(-1.58319,-0.0123887)
(-1.48319,0.087499)
(-1.38319,0.186512)
(-1.28319,0.283662)
(-1.18319,0.377978)
(-1.08319,0.468517)
(-0.983185,0.554374)
(-0.883185,0.634693)
(-0.783185,0.70867)
(-0.683185,0.775566)
(-0.583185,0.834713)
(-0.483185,0.88552)
(-0.383185,0.927478)
(-0.283185,0.96017)
(-0.183185,0.983268)
(-0.0831853,0.996542)
(0.0168147,0.999859)
(0.116815,0.993185)
(0.216815,0.976588)
(0.316815,0.950233)
(0.416815,0.914383)
(0.516815,0.869397)
(0.616815,0.815725)
(0.716815,0.753902)
(0.816815,0.684547)
(0.916815,0.608351)
(1.01681,0.526078)
(1.11681,0.438547)
(1.21681,0.346635)
(1.31681,0.25126)
(1.41681,0.153374)
(1.51681,0.0539554)
(1.61681,-0.0460021)
(1.71681,-0.1455)
(1.81681,-0.243544)
(1.91681,-0.339155)
(2.01681,-0.431377)
(2.11681,-0.519289)
(2.21681,-0.602012)
(2.31681,-0.67872)
(2.41681,-0.748647)
(2.51681,-0.811093)
(2.61681,-0.865435)
(2.71681,-0.91113)
(2.81681,-0.947722)
(2.91681,-0.974844)
(3.01681,-0.992225)
(3.11681,-0.999693)
(3.21681,-0.997172)
(3.31681,-0.984688)
(3.41681,-0.962365)
(3.51681,-0.930426)
(3.61681,-0.889191)
(3.71681,-0.839072)
(3.81681,-0.780568)
(3.91681,-0.714266)
(4.01681,-0.640826)
(4.11681,-0.560984)
(4.21681,-0.475537)
(4.31681,-0.385338)
(4.41681,-0.291289)
(4.51681,-0.19433)
(4.61681,-0.0954289)
(4.71681,0.0044257)
(4.81681,0.104236)
(4.91681,0.203005)
(5.01681,0.299745)
(5.11681,0.393491)
(5.21681,0.483305)
(5.31681,0.56829)
(5.41681,0.647596)
(5.51681,0.720432)
(5.61681,0.78607)
(5.71681,0.843854)
(5.81681,0.893206)
(5.91681,0.933634)
(6.01681,0.964733)
(6.11681,0.986192)
(6.21681,0.997798)
(6.31681,0.999435)
(6.41681,0.991085)
(6.51681,0.972833)
(6.61681,0.94486)
(6.71681,0.907447)
(6.81681,0.860967)
(6.91681,0.805884)
(7.01681,0.742749)
(7.11681,0.672193)

f(25) = 0.991203
#include <iostream>
#include <array>

constexpr const double PI_2{ 6.28318531 };

template<double const &lower, double const &upper>
void foo() {
    static_assert(lower<upper, "invalid lower and upper value");
    
    constexpr size_t size = (upper-lower);
    std::array<int, size> test;
    
    std::cout << lower << " " << upper << " " << test.size() << std::endl;
}

template<double const &V>
struct neg {
  static constexpr double value = -V;
};

int main()
{
    foo<neg<PI_2>::value, PI_2>();
    
    return 0;
}
template<typename T, T const &lower, T const &upper>
void foo() {
    std::cout << lower << " " << upper << std::endl;
}