Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create repeated declaration

Tags:

c++

templates

I was wondering if anyone knows a way of creating repetitive type declarations, and since this might be confusing an example will be helpful:

For our project we need to have function and type declarations like:

    using FunType = std::function<void(double,double,double,double,double,double,double,double)>;
    using DataType = std::tuple<double,double,double,double,double,double,double,double>;

scattered around several files, multiple times, up to 32 doubles (only doubles, if this is important).

I would be happy to replace the manual writing/counting of those doubles, with something in the lines of the following imaginary code:

    using FunType = something_generate_function_decl<8>;
    using DataType = something_generate_datatype_decl<8>

If possible I would like to stay away from boost and its preprocessor library.

Edit to provide some clarification

The big picture is that at some point in the application we get in a series of bytes (representing an array of doubles) with each value having a predefined meaning, we need to do validation on them (each value needs to be verified with several conditions for validity), reject data that is not valid, log the corresponding invalid data with its meaning, pass the meaningful data around the application, from logger module to a dozen of different places including existing functions and also Qt signals with already defined syntax etc... and at some point this will go out from our hands, so that's why I would like to create code as easily readable and verifiable as possible.

Edit2 to provide more clarification

Reading the comments, seemingly there is a lot of confusion about the scope of this question. There is intentionally a lot of information missing from the question which is not relevant to the pure essence of the question which is how to shorten those 8 (or 9, or 12, or 32 doubles) into a more manageable entity. The missing information is our internal way of dealing with the data we receive (we have a project of a large scale, so you can imagine that there are a few layers of abstraction for the data which does automatic validation, conversion, etc... before sending over, so not the entire application is a long list of if/else statements and basic function calls with parameters), the only restriction for the entire thing is that what comes in as a simple array of doubles (representing a message) is validated and then sent over to functions/QT signals/C++11 lambdas which already have a predefined interface. All the information handling and validation is encapsulated into layers of classes which just register themselves somewhere (out of scope for this question) for receiving, storing, validating and sending data, and for example, the FunType (which actually is an internally used type of the message classes) represents the interface of the functions/slots/lambdas where the specific message (with its validated members) will be sent, automatically by some mechanism which gathers all the members into a tuple (DataType) and the using some index_sequence magic with variadic templates the compiler matches the tuple to the required function which at some point in time "subscribed" to this message. @admin if you feel this edit not being relevant, feel free to delete it.

like image 213
Ferenc Deak Avatar asked Jul 30 '20 07:07

Ferenc Deak


People also ask

Can you declare a variable multiple times?

It is okay to declare variables with same name in different functions. Show activity on this post. Variables declared inside a function only exist in the scope of that function, so having the same variable name across different functions will not break anything.

Can we declare variable multiple times in C?

Though you can declare a variable multiple times in your C program, it can be defined only once in a file, a function, or a block of code.

What is multiple declaration in C?

E2238 Multiple declaration for 'identifier' (C++)A function declared in two different ways. A label repeated in the same function. Some declaration repeated, other than an extern function or a simple variable.

Can we declare multiple variables in a single line?

Do not declare more than one variable per declaration. Every declaration should be for a single variable, on its own line, with an explanatory comment about the role of the variable. Declaring multiple variables in a single declaration can cause confusion regarding the types of the variables and their initial values.


2 Answers

tl;dr - this is a frame challenge because I think you're asking the wrong question.

For our project we need to have function and type declarations like:

 using FunType = std::function<void(double,double,double,double,double,double,double,double)>;
 using DataType = std::tuple<double,double,double,double,double,double,double,double>;

Well, don't. If you love pointless repetition so much, you should be doing your calculations by hand instead of using a computer.

I would be happy to replace the manual writing/counting of those doubles, with something in the lines of the following imaginary code:

using FunType = something_generate_function_decl<8>;

Your aspirations are too low. You're just automating the production of bad code, when you could be writing good code instead.

Your final, grudgingly-revealed actual example of what you want to handle:

void fun(double latitude, double longitude, double altitude)
{
  if(latitude > longitude &&
     longitude < 90 && longitude > 9 &&
     altitude > 0)
  {
    fly(longitude, latitude, altitude);
  }
}

(once I removed the tabs and the mixed use of && and and which did nothing to reassure me about the quality of your existing code) ... would be much better handled by using structured types with named fields than any of the things you asked for.

struct LatLongPosition // just in case you have alternative representations
{
    double latitude;
    double longitude;
};

struct AirPosition
{
    LatLongPosition pos;
    double altitude;
};

Now, your function arguments can be strongly-typed: rather than accepting any sequence of 8 or 32 doubles, you can guarantee at compile-time you're passing the correct type of position (if you have more than one), and a position rather than a velocity or momentum or anything else.

Note that there's lots of scope to improve further, but the foundation is to be using structured data types rather than massive flat argument lists in the first place.

like image 197
Useless Avatar answered Oct 12 '22 12:10

Useless


This is easy with Boost.Mp11:

#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/list.hpp>

namespace mp11 = boost::mp11;

template<class... Args>
using make_fn = std::function<void(Args...)>;

using TypeList = mp11::mp_repeat_c<mp11::mp_list<double>, 8>;
using FunType  = mp11::mp_apply<make_fn,    TypeList>;
using DataType = mp11::mp_apply<std::tuple, TypeList>;

An alternative C++14 solution without Boost:

template<template<class...> class Fn, class T, std::size_t n>
struct apply_repeat {
    template<std::size_t... is>
    static Fn<decltype(is, T{})...> 
        get_type(std::index_sequence<is...>);

    using type = decltype(get_type(std::make_index_sequence<n>{}));
};

template<class... Args>
using make_fn = std::function<void(Args...)>;

using FunType  = typename apply_repeat<make_fn,    double, 8>::type;
using DataType = typename apply_repeat<std::tuple, double, 8>::type;

This solution requires a default constructible T. This requirement is satisfied for double.

To lift this requirement we can use type_identity wrapper (will be part of C++20):

template<class T> 
struct type_identity {
    using type = T;
};

template<template<class...> class Fn, class T, std::size_t n>
struct apply_repeat {
    template<std::size_t... is>
    static Fn<typename decltype(is, type_identity<T>{})::type...> 
        get_type(std::index_sequence<is...>);

    using type = decltype(get_type(std::make_index_sequence<n>{}));
};
like image 37
Evg Avatar answered Oct 12 '22 10:10

Evg