Comment puis-je initialiser un object div_t?

Ainsi, l’ordre des membres renvoyés par les fonctions div semble être défini par l’implémentation.

Est le 1 er membre ou est rem ?

Disons que je fais quelque chose comme ça:

 generate(begin(digits), end(digits), [i = div_t{ quot, 0 }]() mutable { i = div(i.quot, 10); return i.rem; }) 

Bien sûr, le problème ici est que je ne sais pas si j’ai initialisé i.quot ou i.rem dans ma capture lambda. Est-ce que l’initialisation i avec div(quot, 1) la seule façon de procéder de la sorte?

MODIFIER:

Je pense que la solution de contournement de VS pourrait ressembler à ceci:

 #include  #include  template struct DTMaker { using D = decltype(div(T{}, T{})); static constexpr D dt = D{0,1}; static constexpr auto quot = dt.quot; }; template ::quot == 0>::type* = nullptr> typename DTMaker::D make_div(const T &quot, const T& rem) { return {quot, rem}; } template ::quot == 1>::type* = nullptr> typename DTMaker::D make_div(const T &quot, const T &rem) { return {rem, qout}; } int main() { div_t d_t = make_div(1, 2); } 

[démo en direct]

ANCIENNE REPONSE:

Si vous utilisez c ++ 17, vous pouvez également essayer d’utiliser une liaison structurée, une fonction constexpr et une surcharge SFINAE pour détecter le champ déclaré en premier dans la structure:

 #include  #include  #include  constexpr bool first_quot() { auto [x, y] = std::div_t{1, 0}; (void)y; return x; } template  std::enable_if_t foo() { int quot = 1; int rem = 0; return {quot, rem}; } template  std::enable_if_t foo() { int quot = 1; int rem = 0; return {rem, quot}; } int main() { foo(); } 

[démo en direct]

Ou encore, utilisation plus simple si constexpr:

 #include  #include  #include  constexpr bool first_quot() { auto [x, y] = std::div_t{1, 0}; (void)y; return x; } std::div_t foo() { int quot = 1; int rem = 0; if constexpr(first_quot()) return {quot, rem}; else return {rem, quot}; } int main() { foo(); } 

[démo en direct]

Vous avez raison de dire que l’ordre des membres est indéterminé. La définition est héritée de C, qui dit explicitement qu’elle est (emphase mienne):

7.20.6.2 Les fonctions div, ldiv et lldiv

3 […] Les structures doivent contenir (dans l’un ou l’autre ordre) les membres quot (le quotient) et rem (le rest), chacun d’eux ayant le même type que les arguments numer et denom . […]

En C, le fait que l’ordre soit non spécifié n’a pas d’importance, et un exemple est inclus spécifiquement concernant div_t :

6.7.8 Initialisation

34 EXEMPLE 10 Les membres de structure peuvent être initialisés sur des valeurs non nulles sans dépendre de leur ordre:

 div_t answer = { .quot = 2, .rem = -1 }; 

Malheureusement, C ++ n’a jamais adopté cette syntaxe.

Je choisirais probablement une affectation simple dans une fonction d’assistance:

 div_t make_div_t(int quot, int rem) { div_t result; result.quot = quot; result.rem = rem; return result; } 

Pour les valeurs plain int , que vous utilisiez l’initialisation ou l’affectation importe peu, elles ont le même effet.

Votre division par 1 est également une option valable.

Pour citer le projet de norme C11, projet N1570, § 7.22.6.2

Les fonctions div, ldiv et lldiv renvoient une structure de type div_t, ldiv_t et lldiv_t, comprenant à la fois le quotient et le rest. Les structures doivent contenir (dans l’un ou l’autre ordre) les membres quot (le quotient) et rem (le rest), chacun d’eux ayant le même type que les arguments numer et denom.

Donc, dans ce cas, div_t est une structure POD simple, composée de deux int s.

Pour que vous puissiez l’initialiser comme toute structure, votre chemin serait quelque chose que j’aurais fait aussi. C’est aussi portable.

Sinon, je ne trouve aucun mécanisme spécial pour les initialiser, ni dans le standard C, ni dans le standard C ++. Mais pour POD, alias Plain Old Datatypes, ce n’est pas nécessaire.

Essayez quelque chose comme ça 🙂

 int quot = 10; auto l = [i = [=] { div_t tmp{}; tmp.quot = quot; return tmp; }()]() mutable { i = div(i.quot, 10); return i.rem; }; 

Cela ressemble à utiliser un littéral composé en C. 🙂

ou vous pouvez simplifier la tâche en définissant la variable i dehors de l’expression lambda et l’utiliser dans le lambda par référence.

Par exemple

 int quot = 10; dov_t i = {}; i.quot = quot; auto l = [&i]() { i = div(i.quot, 10); return i.rem; }; 

Vous pouvez utiliser un ternaire pour initialiser ceci:

 generate(rbegin(digits), rend(digits), [i = div_t{ 1, 0 }.quot ? div_t{ quot, 0 } : div_t{ 0, quot }]() mutable { i = div(i.quot, 10); return i.rem; }); 

gcc6.3 par exemple comstackra un code identique avec le ternaire et sans le ternaire .

D’autre part, clang3.9 comstack un code plus long avec le ternaire que sans le ternaire .

Donc, si le ternaire est optimisé en sortie varie selon les compilateurs. Mais dans tous les cas, cela vous donnera un code indépendant de l’implémentation qui n’exige pas l’écriture d’une fonction secondaire.


Incidemment, si vous êtes en div_t de créer une fonction d’assistance pour créer un div_t (ou l’un des autres retours div ), vous pouvez le faire comme ceci:

 template  enable_if_t(), declval())){ 1, 0 }.quot != 0, decltype(div(declval(), declval()))> make_div(const T quot, const T rem) { return { quot, rem }; } template  enable_if_t(), declval())){ 1, 0 }.quot == 0, decltype(div(declval(), declval()))> make_div(const T quot, const T rem) { return { rem, quot }; } 

Notez que cela fonctionne sur gcc mais ne parvient pas à comstackr sur Visual Studio en raison de certaines non-conformités.

Ma solution utilise une fonction constexpr qui encapsule et exécute elle-même une fonction lambda qui détermine et initialise le div_t correct en fonction des parameters du modèle.

 template  constexpr auto make_div(const T quot, const T rem) { return [&]() { decltype(std::div(quot, rem)) result; result.quot = quot; result.rem = rem; return result; }(); } 

Cela fonctionne avec MSVC15, gcc 6.3 et clang 3.9.1.

http://rextester.com/AOBCH32388


Le lambda nous permet d’initialiser une valeur pas à pas au sein d’une fonction constexpr. Ainsi, nous pouvons définir quot and rem correctement et indépendamment de l’ordre dans lequel ils apparaissent dans le type de données lui-même.

En l’intégrant dans une fonction constexpr, nous permettons au compilateur d’optimiser complètement l’appel à make_div :

clang: https://godbolt.org/g/YdZGkX

gcc: https://godbolt.org/g/sA61LK