Is there an existing name for this type and function?
Asked Answered
I

5

24

There are 2 hard problems in computer science: cache invalidation, naming things and off-by-one errors.

This is about the 2nd problem: naming things.

I'm looking if this technique or type has been used somewhere else already and has a name. dichotomy is an ok name, but bools_at_compile_time is a horrible one.

using dichotomy_t = std::variant<std::false_type, std::true_type>;
// (or a struct that inherits from that, and overloads operator bool())

constexpr dichotomy_t dichotomy( bool b ) {
  if (b) return std::true_type{};
  return std::false_type{};
}
template<class F, class...Bools>
constexpr auto bools_at_compile_time( F&& f, Bools...bools ) {
  static_assert( (std::is_same<Bools, bool>{} && ...) );
  return std::visit( std::forward<F>(f), dichotomy(bools)... );
}

dichotomy_t is a variant between true and false. Its runtime representation is 0 or 1.

What this lets you do is:

auto foo( bool x, bool y ) { // <-- x and y are run-time bools here
  auto func = [&](auto x, auto y) {
    return some_template<x,y>(); // <-- x and y are compile-time bools here
  };
  return bools_at_compile_time( func, x, y ); // <-- converts runtime to compile time bools
}

Is there a name for dichotomy_t or the more general bools_at_compile_time technique? I'm looking for a name that is well known in any community (even a non-C++ one), even a verb that describes "taking a runtime value and creating a switch and a set of compile time value in generated code to pick between" better than a sentence.

Live example

A good answer would include the name, citations/quotes describing what that name means, examples of that named thing in use in the other context, and evidence that this name is equivalent to or inclusive of the above type/value and function.

(It may help to find a name the generalization of this would be an enum instead of a bool, which has a fixed number of known states, and a switch/case map that converts the runtime value into a compile-time constant in each case clause.)

Ilex answered 3/5, 2019 at 19:17 Comment(12)
I'm trying to wrap my head around what this actually does. Is it basically a wrapper around something like bool b = ...; if (b) func<true>(...); else func<false>(...); ? (but for all combinations of values for multiple bools)Rehabilitation
@Rehabilitation Yes, much like that. It converts a runtime bool into a compile time bool.Ilex
"x and y are compile-time bools here" Um, that doesn't work. Function parameters are not constant expressions and therefore cannot be used to instantiate a template.Ong
@NicolBolas They have a constexpr operator bool that does not depend on the constexprness of *this to be evaluated at compile time. So while x is not a constexpr value, static_cast<bool>(x) is a constant expression, and that is what passing it to a template does. It works in all major current compilers; not in some older ones.Ilex
Would this allow me to break up any runtime integer into its compile- time bits? In other words, would it create all 2^32-1 possible instantiation?Cyanohydrin
@André Yes, but that seems like a bad idea. No, not seems. Is. That is a bad idea. (and compilers will choke before getting there in practice). And there are generally 2^32 different 32 bit ints, no -1. But yes, techniques similar to this can create O(2^n) assembly from O(n) code easily; that is not advised for anything except small n. But that is a side issue; I'm looking for a name for this that has been used elsewhere.Ilex
@André: It's unlikely you could create a variant that large.Ong
I would say dispatcher, even if probably too generic.Clunk
JIT proposal would allow to instantiate template with runtime values :-)Clunk
I've heard "lifting" used in this context before. Lifting runtime values to types.Sporogonium
If the function were returned like a closure instead of invoked, it would be the Factory Pattern.Sapper
I'd suggest a suffix meta or something like that for meta-functions. I read theses articles but never found a hint about a general used keyword related to your question: C++ Core Guidelines: Programming at Compile Time with the Type-Traits and C++ Core Guidelines: Programming at Compile Time with the Type-Traits IIBourke
T
9

I do not know of any existing names for this pattern, but if you take a good look at how the STL is naming things, you can use name close enough to make your code explicit.

I also liked the dispatcher_t idea from @Jarod42 , I think it is more generic than dichotomy_t or n_chotomy_t.

dichotomy() could be called make_variant(b). Since it will return the std::variant value of a boolean given in argument. Much like std::make_tuple makes a tuple from multiple arguments.

I would suggest to replace bools_at_compile_time by static_eval. Much like static_assert makes an assertion at compile time.

Not that if eval is not the correct adjective for your use case you can easily adapt it static_*.

#include <type_traits>
#include <variant>
#include <utility>

using dichotomy_t = std::variant<std::false_type, std::true_type>;
// (or a struct that inherits from that, and overloads operator bool())

constexpr dichotomy_t make_variant( bool b ) {
  if (b) return std::true_type{};
  return std::false_type{};
}
template<class F, class...Bools>
constexpr auto static_eval( F&& f, Bools...bools ) {
  static_assert( (std::is_same<Bools, bool>{} && ...) );
  return std::visit( std::forward<F>(f), make_variant(bools)... );
}

template<bool x, bool y>
auto some_template() {
    return x || y;
}

auto foo( bool x, bool y ) { // <-- x and y are run-time bools here
  auto func = [&](auto x, auto y) {
    return some_template<x,y>(); // <-- x and y are compile-time bools here
  };
  return static_eval( func, x, y ); // <-- converts runtime to compile time bools
}

#include <iostream>

int main() {
    std::cout << foo( true, true ) << "\n";
}
Thoraco answered 6/5, 2019 at 15:57 Comment(1)
Whereas static_assert is really done at compile-time, static_eval would be done at compile-time only in const expr context (as any constexpr functions).Clunk
P
6

Generation of specialized version of a function is called cloning. (see Procedure Cloning). The term clone is used to name the specialized function generated by the optimizer during constant propagation (see gcc doc).

The set of specialized functions generated by std::visit could be named clone set.

This set is generated for all combinations of argument value. This term combination let us suppose that the set of possible value of each argument is finite.

So we could have a long name for the set of clones such as, set of clones for all combination of argument values. An other option more obscure but shorter could be combinatorial clone set.

As already pointed out, the action of selecting the right function to call in term of the argument could be called dispatch.

So I would propose combinatiorial_clone_set_dispatch or dispatch_in_combinatorial_clone_set ...

Prostitute answered 10/5, 2019 at 18:36 Comment(0)
B
2

As I am unaware of a similar implementation, I'll just go type by type with bikeshed colors.


using boolean_t = std::variant<std::false_type, std::true_type>;

This is pretty self-explanatory, as it's a variant that can store one or the other of the std::integral_constants for true or false. It's kind of a bool, but bool_t is likely to cause confusion. An alternative is boolean_variant, but that may be too verbose.


constexpr boolean_t to_boolean_t( bool b ) {
  if (b) return std::true_type{};
  return std::false_type{};
}

I started with convert_bool, but that's a bit too generic. to_boolean_t is more expressive. make_boolean_t is also a possibility, as it is basically a boolean_t factory function. Note: I previously chose to_constexpr_boolean, but that's unnecessarily verbose.


template<class F, class...Bools>
constexpr auto static_eval( F&& f, Bools...bools ) {
  static_assert( (std::is_same<Bools, bool>{} && ...) );
  return std::visit( std::forward<F>(f), to_boolean_t(bools)... );
}

I chose static_eval here as I like Clonk's reasoning, but "static" has contextual meaning in C++, so alternatives are (in no order of importance):

  • boolean_visit
  • static_visit
  • constexpr_eval
  • constexpr_visit
Bentley answered 11/5, 2019 at 9:27 Comment(0)
S
1

You issue was: (bold mine)

I'm looking for a name that is well known in any community (even a non-C++ one), even a verb that describes "taking a runtime value and creating a switch and a set of compile time value in generated code to pick between" better than a sentence.

There is, but only if you will adopt it from a related field of science:

The U.S. National Electrical Code (NEC) defines a switchboard as "a large single panel, frame, or assembly of panels on which are mounted, on the face, back, or both, switches, over-current and other protective devices, buses, and usually instruments". The role of a switchboard is to allow the division of the current supplied to the switchboard into smaller currents for further distribution and to provide switching, current protection and (possibly) metering for those various currents. In general, switchboards may distribute power to transformers, panelboards, control equipment, and, ultimately, to individual system loads.

Adopting this thinking, you would simply call it switches.

I will also add that it is quite unusual to specify (ie. repeat) the storage type or cv-qualifier, etc. in type/variable names - even when not directly visible you would usually leave that as implicit - unless it really needs to be emphasized.

Sharpeared answered 13/5, 2019 at 11:47 Comment(0)
B
0

Maybe staticCastValue? As in you are casting a dynamic(runtime) value to a static value. Can be used with templates or overloads for different types.

Or maybe assertInmutable? As in you are converting a mutable type into an inmutable one.

Or perhaps expressConstantly? As in you are expressing the same value but in constant form. A form similar to constexpr.

A wild one: staticBifurcate? As in theres two things to choose from, thus a bifurcation is there.

bifurcate verb /ˈbʌɪfəkeɪt/ 1. divide into two branches or forks. "just below Cairo the river bifurcates"

Or finally convertToConstExpr? Explicitly saying that the value will be converted to something akin or compatible with a constexpr.

Bagby answered 9/5, 2019 at 20:52 Comment(1)
maybe as a bit of a last attempt, although perhaps a bit silly: chrono_compilerize as in you convert the value to compile time compatibleBagby

© 2022 - 2024 — McMap. All rights reserved.