可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
So the order of the members returned from the div
functions seems to be implementation defined.
Is quot
the 1st member or is rem
?
Let's say that I'm doing something like this:
generate(begin(digits), end(digits), [i = div_t{ quot, 0 }]() mutable {
i = div(i.quot, 10);
return i.rem;
})
Of course the problem here is that I don't know if I initialized i.quot
or i.rem
in my lambda capture. Is intializing i
with div(quot, 1)
the only cross platform way to do this?
回答1:
EDIT:
I think the VS workaround could look like this:
#include <cstdlib>
#include <type_traits>
template<class T>
struct DTMaker {
using D = decltype(div(T{}, T{}));
static constexpr D dt = D{0,1};
static constexpr auto quot = dt.quot;
};
template <class T, typename std::enable_if<DTMaker<T>::quot == 0>::type* = nullptr>
typename DTMaker<T>::D make_div(const T ", const T& rem) { return {quot, rem}; }
template <class T, typename std::enable_if<DTMaker<T>::quot == 1>::type* = nullptr>
typename DTMaker<T>::D make_div(const T ", const T &rem) { return {rem, qout}; }
int main() {
div_t d_t = make_div(1, 2);
}
[live demo]
OLD ANSWER:
If you are using c++17 you could also try to use structured binding, constexpr function and SFINAE overloading to detect which field is declared first in the structure:
#include <cstdlib>
#include <algorithm>
#include <iterator>
constexpr bool first_quot() {
auto [x, y] = std::div_t{1, 0};
(void)y;
return x;
}
template <bool B = first_quot()>
std::enable_if_t<B, std::div_t> foo() {
int quot = 1;
int rem = 0;
return {quot, rem};
}
template <bool B = first_quot()>
std::enable_if_t<!B, std::div_t> foo() {
int quot = 1;
int rem = 0;
return {rem, quot};
}
int main() {
foo();
}
[live demo]
Or even simpler use if constexpr:
#include <cstdlib>
#include <algorithm>
#include <iterator>
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();
}
[live demo]
回答2:
You're right that the order of the members is unspecified. The definition is inherited from C, which explicitly states it is (emphasis mine):
7.20.6.2 The div, ldiv, and lldiv functions
3 [...] The structures shall contain (in either order) the members quot
(the quotient) and rem
(the remainder), each of which has the same type as the arguments numer
and denom
. [...]
In C, the fact that the order is unspecified doesn't matter, and an example is included specifically regarding div_t
:
6.7.8 Initialization
34 EXAMPLE 10 Structure members can be initialized to nonzero values without depending on their order:
div_t answer = { .quot = 2, .rem = -1 };
Unfortunately, C++ never adopted this syntax.
I'd probably go for simple assignment in a helper function:
div_t make_div_t(int quot, int rem) {
div_t result;
result.quot = quot;
result.rem = rem;
return result;
}
For plain int
values, whether you use initialisation or assignment doesn't really matter, they have the same effect.
Your division by 1
is a valid option as well.
回答3:
To quote the C11 Standard Draft N1570 §7.22.6.2
The div, ldiv, and lldiv functions return a structure of type div_t, ldiv_t, and lldiv_t, respectively, comprising both the quotient and the remainder. The structures shall contain (in either order) the members quot (the quotient) and rem (the remainder), each of which has the same type as the arguments numer and denom.
So in this case div_t
is a plain POD struct, consisting of two int
s.
So you can initialize it like every plain struct, your way would be something I would have done too. It's also portable.
Otherwise I can't find anything special mechanism to initialize them, neither in the C nor in the C++ standard. But for POD aka Plain Old Datatypes, there isn't any need for.
回答4:
Try something like this:)
int quot = 10;
auto l = [i = [=] { div_t tmp{}; tmp.quot = quot; return tmp; }()]() mutable
{
i = div(i.quot, 10);
return i.rem;
};
It looks like using a compound literal in C.:)
or you can simplify the task by defining the variable i
outside the lambda expression and use it in the lambda by reference.
For example
int quot = 10;
dov_t i = {};
i.quot = quot;
auto l = [&i]()
{
i = div(i.quot, 10);
return i.rem;
};
回答5:
You can use a ternary to initialize this:
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 for example will compile identical code with the ternary and without the ternary.
On the other hand clang3.9 compiles longer code with the ternary than it does without the ternary.
So whether the ternary is optimized out will vary between compilers. But in all cases it will give you implementation independent code that doesn't require a secondary function to be written.
Incidentally if you are into creating a helper function to create a div_t
(or any of the other div
returns) you can do it like this:
template <typename T>
enable_if_t<decltype(div(declval<T>(), declval<T>())){ 1, 0 }.quot != 0, decltype(div(declval<T>(), declval<T>()))> make_div(const T quot, const T rem) { return { quot, rem }; }
template <typename T>
enable_if_t<decltype(div(declval<T>(), declval<T>())){ 1, 0 }.quot == 0, decltype(div(declval<T>(), declval<T>()))> make_div(const T quot, const T rem) { return { rem, quot }; }
Note this does work on gcc but fails to compile on Visual Studio because of some non-conformity.
回答6:
My solution uses a constexpr function that itself wraps and executes a lambda function that determines and initializes the correct div_t
depending on the template parameters.
template <typename T>
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;
}();
}
This works with MSVC15, gcc 6.3 and clang 3.9.1.
http://rextester.com/AOBCH32388
The lambda allows us to initialize a value step by step within a constexpr function. So we can set quot
and rem
correctly and independently from the order they appear in the datatype itself.
By wrapping it into a constexpr function we allow the compiler to completely optimize the call to make_div
:
clang: https://godbolt.org/g/YdZGkX
gcc: https://godbolt.org/g/sA61LK