在C ++ 14简单constexpr LookUpTable [英] Simple constexpr LookUpTable in C++14

查看:121
本文介绍了在C ++ 14简单constexpr LookUpTable的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想根据整数数组制作一个简单 LookUpTable ,其中的想法是在编译时计算



尝试使用它可能用于任何其他未来的各种整数类型的表格,我可能需要它作为一个模板



所以我有一个 LookUpTable.h



  #ifndef LOOKUPTABLE_H 
#define LOOKUPTABLE_H

#include< stdexcept> // out_of_range

template< typename T,std :: size_t NUMBER_OF_ELEMENTS>
class LookUpTableIndexed
{
private:
// constexpr static std :: size_t NUMBER_OF_ELEMENTS = N;

// LookUpTable
T m_lut [NUMBER_OF_ELEMENTS] {}; // ESSENTIAL T COMPILE-TIME INTERPRETER的默认构造函数!

public:
//构造和填充LookUpTable,
//值的INDICES映射到存储的DATA值
constexpr LookUpTableIndexed():m_lut {}
{
// ctor
}

//返回存储的值的数量
constexpr std :: size_t size()const {return NUMBER_OF_ELEMENTS;}

//返回给定INDEX的数据值
constexpr T& operator [](std :: size_t n)
{
if(n< NUMBER_OF_ELEMENTS)
return m_lut [n]
else throw std :: out_of_range(LookUpTableIndexed []:OutOfRange!);
}
constexpr const T& operator [](std :: size_t n)const
{
if(n< NUMBER_OF_ELEMENTS)
return m_lut [n]
else throw std :: out_of_range(LookUpTableIndexed [] const:OutOfRange!);
}

使用iterator = T *;

//返回LookUpTable的开始和结束
constexpr iterator begin(){return& m_lut [0];}
constexpr iterator end(){return& m_lut [ NUMBER_OF_ELEMENTS];}
};

#endif // LOOKUPTABLE_H

在一个快速衰减整数信号wrt和整数距离的类中。



这只是一个示例用法: Foo.h

  #ifndef FOO_H 
#define FOO_H

#include< limits> // max,digits
#include< stdlib.h> // abs

#includeLookUpTable.h// LookUpTableIndexed

class Foo
{
private:
template< typename TDistance,
TDistance MAXIMUM_DISTANCE,
std :: size_t NUMBER_OF_DIGITS>
struct DistanceAttenuation
{
private:
//可以在此类型中保存的最大值
// constexpr auto MAXIMUM_DISTANCE = std :: numeric_limits< TDistance> ;: :max();

//此类型使用的位数
// constexpr auto NUMBER_OF_DIGITS = std :: numeric_limits< TDistance> :: digits;

// LookUpTable
LookUpTableIndexed< TDistance,NUMBER_OF_DIGITS> m_attenuationRangeUpperLimit {}; // ESSENTIAL LookUpTable COMPILE-TIME INTERPRETER的默认构造函数!

//返回到BIT-SHIFT-RIGHT的位数,衰减一些信号
//给定它与源的距离
constexpr std :: size_t attenuateBy(const TDistance距离)
{
for(std :: size_t i {NUMBER_OF_DIGITS};(i> 0); --i)
{
//当距离超过上限,保持尝试值
if(distance> = m_attenuationRangeUpperLimit [i-1])$ ​​b $ b {
//找到RANGE给定距离占用
return
}
}
throw std :: logic_error(DistanceAttenuation :: attenuateBy(Can not attenuate signal using given distance!));
}

public:
//计算信号的距离校正因子
//因此它们可以被衰减以模拟距离对信号强度的影响
// ...使用距离的反向平方关系到信号强度
constexpr DistanceAttenuation():m_attenuationRangeUpperLimit {}
{
// ctor

//填充LookUpTable
for(std :: size_t i {0};(i {
TDistance goo = 0; //不是衰减计算
TDistance hoo = 0; // ** FOR TEST ONLY!**
m_attenuationRangeUpperLimit [i] = MAXIMUM_DISTANCE - goo - hoo;
}
static_assert((m_attenuationRangeUpperLimit [0] == MAXIMUM_DISTANCE),
DistanceAttenuation:Failed to Build LUT!
}

//通过距离
//的效果衰减信号s,通过某个因子a,其中;
//正向贡献值向ZERO向下衰减
//负向上ZERO
constexpr signed int attenuateSignal(const signed int s,const int a)
{
return(s <0)? - (abs(s)> a):
(abs(s)> a);
}
constexpr signed int attenuateSignalByDistance(const signed int s,const TDistance d)
{
return attenuateSignal(s,attenuateBy(d));
}

};

使用SDistance_t = unsigned int;

constexpr static auto m_distanceAttenuation = DistanceAttenuation< SDistance_t,
std :: numeric_limits< SDistance_t> :: max(),
std :: numeric_limits< SDistance_t> :: digits> );

public:
Foo(){}
〜Foo(){}

//做一些整数foo
signed int attenuateFoo (signed int signal,SDistance_t distance){return m_distanceAttenuation :: attenuateSignalByDistance(signal,distance);}

};

#endif // FOO_H

我尝试过几种方法,使用 CppCon 2015:Scott Schurrconstexpr:Applications和其他人的YouTube视频教程,但不会编译出错误;

 错误:'constexpr static auto m_distanceAttenuation ...'在其定义之前使用

且静态断言失败

 错误:静态断言的非常量条件



表示在编译时未计算任何内容。



我是C ++的新手。



我知道我在做一些明显的事,但我不知道是什么。



我是在使用 static constexpr 吗?



> numeric_limits are constexpr?



我做错了什么?
谢谢。

解决方案

一些意见



1) m_distanceAttenuation 时, Foo code>和 DistanceAttenuation Foo 的一部分,因此不完整。



不幸的是,你不能初始化一个不完整类型的 static constexpr 成员(更好地解释由jogojapan 在此回答)。



建议:定义 DistanceAttenuation 它之外(和之前) Foo 所以它是一个完整的类型,可以用于初始化 m_distanceAttenuation ;像

 模板< typename TDistance,
TDistance MAXIMUM_DISTANCE,
std :: size_t NUMBER_OF_DIGITS&
struct DistanceAttenuation
{
// ...
};

class Foo
{
// ...
};

2)在C ++ 14中, constexpr 方法不是 const 方法;建议:在 const 中定义以下方法,或者您不能在一些 constexpr 表达式中使用它们

  constexpr std :: size_t attenuateBy(const TDistance distance)const 
constexpr signed int attenuateSignal(const signed int s,const int a) const
constexpr signed int attenuateSignalByDistance(const signed int s,const TDistance d)const

3 )在 attenuateBy()中,在中测试是真的

  for(std :: size_t i {NUMBER_OF_DIGITS  -  1};(i> = 0); --i)

因为 std :: size_t > = 0 ,因此 for 进入循环,从不退出;建议:重新定义 i int long



4)在 attenuateFoo()中使用 m_DistanceAttenuation 定义为 m_distanceAttenuation ;建议:在 attenuateFoo()中调用变量的正确名称

< $ c> ::
运算符使用$ c> attenuateSignalByDistance()
建议:使用运算符,因此(也考虑点(4))

  signed int attenuateFoo(signed int signal,SDistance_t distance)
{return m_distanceAttenuation.attenuateSignalByDistance(signal,distance);}


I am trying to make a simple LookUpTable based on an array of integers, where the idea is to have it calculated at compile time.

Trying to make it possible to use it for any other future tables of various integer types I might have, I need it as a template.

So I have a LookUpTable.h

#ifndef LOOKUPTABLE_H
#define LOOKUPTABLE_H

#include <stdexcept> // out_of_range

template <typename T, std::size_t NUMBER_OF_ELEMENTS>
class LookUpTableIndexed
{
    private:
        //constexpr static std::size_t NUMBER_OF_ELEMENTS = N;

        // LookUpTable
        T m_lut[ NUMBER_OF_ELEMENTS ] {}; // ESSENTIAL T Default Constructor for COMPILE-TIME INTERPRETER!

    public:
        // Construct and Populate the LookUpTable such that;
        //   INDICES of values are MAPPED to the DATA values stored
        constexpr LookUpTableIndexed() : m_lut {}
        {
            //ctor
        }

        // Returns the number of values stored
        constexpr std::size_t size() const {return NUMBER_OF_ELEMENTS;}

        // Returns the DATA value at the given INDEX
        constexpr T& operator[](std::size_t n)
        {
            if (n < NUMBER_OF_ELEMENTS)
                return m_lut[n];
            else throw std::out_of_range("LookUpTableIndexed[] : OutOfRange!");
        }
        constexpr const T& operator[](std::size_t n) const
        {
            if (n < NUMBER_OF_ELEMENTS)
                return m_lut[n];
            else throw std::out_of_range("LookUpTableIndexed[] const : OutOfRange!");
        }

        using iterator = T*;

        // Returns beginning and end of LookUpTable
        constexpr iterator begin() {return &m_lut[0                 ];}
        constexpr iterator end  () {return &m_lut[NUMBER_OF_ELEMENTS];}
};

#endif // LOOKUPTABLE_H

And I'm trying to use it in a class for rapid attenuation of an integer signal wrt an integer distance.

eg. This is just a sample usage as Foo.h

#ifndef FOO_H
#define FOO_H

#include <limits>   // max, digits
#include <stdlib.h> // abs

#include "LookUpTable.h" // LookUpTableIndexed

class Foo
{
private:
    template <typename    TDistance,
              TDistance   MAXIMUM_DISTANCE,
              std::size_t NUMBER_OF_DIGITS>
    struct DistanceAttenuation
    {
    private:
        // Maximum value that can be held in this type
        //constexpr auto MAXIMUM_DISTANCE = std::numeric_limits<TDistance>::max();

        // Number of bits used by this type
        //constexpr auto NUMBER_OF_DIGITS = std::numeric_limits<TDistance>::digits;

        // LookUpTable
        LookUpTableIndexed<TDistance, NUMBER_OF_DIGITS> m_attenuationRangeUpperLimit {}; // ESSENTIAL LookUpTable Default Constructor for COMPILE-TIME INTERPRETER!

        // Returns the number of bits to BIT-SHIFT-RIGHT, attenuate, some signal
        // given its distance from source
        constexpr std::size_t attenuateBy(const TDistance distance)
        {
            for (std::size_t i {NUMBER_OF_DIGITS}; (i > 0); --i)
            {
                // While distance exceeds upper-limit, keep trying values
                if (distance >= m_attenuationRangeUpperLimit[i - 1])
                {
                    // Found RANGE the given distance occupies
                    return (i - 1);
                }
            }
            throw std::logic_error("DistanceAttenuation::attenuateBy(Cannot attenuate signal using given distance!)");
        }

    public:
        // Calculate the distance correction factors for signals
        // so they can be attenuated to emulate the the effects of distance on signal strength
        // ...USING THE INVERSE SQUARE RELATIONSHIP OF DISTANCE TO SIGNAL STRENGTH
        constexpr DistanceAttenuation() : m_attenuationRangeUpperLimit {}
        {
            //ctor

            // Populate the LookUpTable
            for (std::size_t i {0}; (i < NUMBER_OF_DIGITS); ++i)
            {
                TDistance goo = 0; // Not an attenuation calculation
                TDistance hoo = 0; // **FOR TEST ONLY!**
                m_attenuationRangeUpperLimit[i] = MAXIMUM_DISTANCE - goo - hoo;
            }
            static_assert((m_attenuationRangeUpperLimit[0] == MAXIMUM_DISTANCE),
                          "DistanceAttenuation : Failed to Build LUT!");
       }

        // Attenuate the signal, s, by the effect of the distance 
        // by some factor, a, where;
        // Positive contribution values are attenuated DOWN toward ZERO
        // Negative                                    UP          ZERO
        constexpr signed int attenuateSignal(const signed int s, const int a)
        {
            return (s < 0)? -(abs(s) >> a) :
                             (abs(s) >> a);
        }
        constexpr signed int attenuateSignalByDistance(const signed int s, const TDistance d)
        {
            return attenuateSignal(s, attenuateBy(d));
        }

    };

    using SDistance_t = unsigned int;

    constexpr static auto m_distanceAttenuation = DistanceAttenuation<SDistance_t,
                                                                      std::numeric_limits<SDistance_t>::max(),
                                                                      std::numeric_limits<SDistance_t>::digits>();

public:
    Foo() {}
    ~Foo() {}

    // Do some integer foo
    signed int attenuateFoo(signed int signal, SDistance_t distance) {return m_distanceAttenuation::attenuateSignalByDistance(signal, distance);}

};

#endif // FOO_H

I have tried to do this several ways, using the youtube video tutorial by CppCon 2015: Scott Schurr "constexpr: Applications" and others, but it won't compile giving the error;

error: 'constexpr static auto m_distanceAttenuation...' used before its definition

and the static asserts fail with

error: non-constant condition for static assertion

indicating it isn't calculating anything at compile-time.

I'm new to C++.

I know I'm doing something obvious but I don't know what it is.

Am I misusing static or constexpr?

numeric_limits are constexpr?

What am I doing wrong? Thank you.

解决方案

Some observations

1) as observed by michalsrb, Foo isn't complete when you initialize m_distanceAttenuation and DistanceAttenuation is part of Foo, so is incomplete.

Unfortunately you can't initialize a static constexpr member with an incomplete type (as better explained by jogojapan in this answer).

Suggestion: define DistanceAttenuation it outside (and before) Foo; so it's a complete type and can be used to initialize m_distanceAttenuation; something like

 template <typename    TDistance,
           TDistance   MAXIMUM_DISTANCE,
           std::size_t NUMBER_OF_DIGITS>
 struct DistanceAttenuation
 {
   // ...
 };

class Foo
{
  // ...
};

2) in C++14, a constexpr method isn't a const method; suggestion: define the following method as const too or you can't use they in some constexpr expressions

constexpr std::size_t attenuateBy (const TDistance distance) const
constexpr signed int attenuateSignal(const signed int s, const int a) const
constexpr signed int attenuateSignalByDistance(const signed int s, const TDistance d) const

3) in attenuateBy(), the test in the following for is ever true

for (std::size_t i {NUMBER_OF_DIGITS - 1}; (i >= 0); --i)

because a std::size_t is ever >= 0, so the for goes in loop and never exit; suggestion: redefine i as int or long

4) in attenuateFoo() you use m_DistanceAttenuation where the variable is defined as m_distanceAttenuation; suggestion: correct che name of the variable used

5) in attenuateFoo() you call the method attenuateSignalByDistance() using the :: operator; suggestion: use the . operator, so (considering point (4) too)

signed int attenuateFoo(signed int signal, SDistance_t distance)
 {return m_distanceAttenuation.attenuateSignalByDistance(signal, distance);}

这篇关于在C ++ 14简单constexpr LookUpTable的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆