Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++, how to use a subset of all types

I'm writing a function which I want to accept a distribution as a parameter. Let's say the following:

#include<random>
#include<iostream>
using namespace std;

random_device rd;
mt19937 gen(rd());

void print_random(uniform_real_distribution<>& d) {
    cout << d(gen);
}

Now is there a way to generalise this code, in a short way, in C++ such that it would accept all distributions and distributions only (otherwise the compiler should complain)? Edit: To clarify, the solution should also be able to accept only a subset of all distributions (which would have to be pre-specified).

I would for example accept the ability to define a type as a collection of allowed types but it would be even better if there is already a type which has this property for distributions.

like image 273
Haffi112 Avatar asked Dec 15 '14 11:12

Haffi112


People also ask

What is the difference between ⊆ and ⊂?

The symbol "⊆" means "is a subset of". The symbol "⊂" means "is a proper subset of". Since all of the members of set A are members of set D, A is a subset of D.

What does this mean ⊆?

In set theory, a subset is denoted by the symbol ⊆ and read as 'is a subset of'. Using this symbol we can express subsets as follows: A ⊆ B; which means Set A is a subset of Set B. Note: A subset can be equal to the set.

Why is C not a subset of C++?

In the strict mathematical sense, C isn't a subset of C++. There are programs that are valid C but not valid C++ and even a few ways of writing code that has a different meaning in C and C++. However, C++ supports every programming technique supported by C95 (C90 plus an Amendment) and earlier.

How do you subset a list?

To subset lists we can utilize the single bracket [ ] , double brackets [[ ]] , and dollar sign $ operators. Each approach provides a specific purpose and can be combined in different ways to achieve the following subsetting objectives: Subset list and preserve output as a list.


1 Answers

There is no such traits in standard library. You can just write something like

template<typename T>
struct is_distribution : public std::false_type {};

and specialize for each type, that is distribution

template<typename T>
struct is_distribution<std::uniform_int_distribution<T> > :
public std::true_type {};

Then just

template<typename Distr>
typename std::enable_if<is_distribution<Distr>::value>::type 
print_random(Distr& d)
{
    cout << d(gen);
}

Also, you can use something like concepts-lite (but with decltypes, since there is no this feature now), it can not work in some cases. In standard there are rules, that should any distribution follow (n3376 26.5.1.6/Table 118).

template<typename D>
constexpr auto is_distribution(D& d) ->
decltype(std::declval<typename D::result_type>(),
std::declval<typename D::param_type>(),
d.reset(), d.param(), d.param(std::declval<typename D::param_type>()), true);

template<typename D>
auto print_random(D& d) -> decltype(is_distribution(d), void())
{
}

If you want just check that type is callable with some generator and execution of this call returns result_type you can just simplify function

template<typename D>
auto is_distribution(D& d) ->
decltype(std::is_same<typename D::result_type,
decltype(d(*static_cast<std::mt19937*>(0)))>::value);

all this things will be much simple, when concepts-lite will be available in standard.

like image 144
ForEveR Avatar answered Nov 06 '22 20:11

ForEveR