Reputation: 25
I'm working on a rendering engine using Vulkan and Visual Studio 2017, and I bumped into the following type of problem recently.
I have a template struct template<uint32_t id> struct A;
. This struct is defined (in separate header files) for id=0, ... , N-1
. All of the definitions have a static constexpr std::array<B, M(id)> member
for some struct B
and number M
depending on id
. I have a constexpr function (and a helper function) which for a given value b
of type B
counts how many elements of all of these arrays equal to b
. It looks something like this:
Helper function:
template<size_t Size>
constexpr void count_in_array(B b, const std::array<B, Size>& a, uint32_t& count)
{
for(auto& e : a)
{
if(e==b)
++count;
}
}
Main function:
template<uint32_t... ids>
constexpr uint32_t count_in_arrays(B b, std::index_sequence<ids...>)
{
uint32_t count=0;
auto l ={ (count_in_array(b, A<ids>::member, count), 0)... };
return count;
}
When I compile, I get a C1001 internal compiler error. The strange thing is that my funcions work, because if I use them to define a constexpr variable
constexpr uint32_t var=count_in_arrays(b, std::make_index_sequence<N>());
(for a constexpr B b
),
and I hoover the mouse over that variable, I see the computed (and correct) number in the appearing rectangle.
I am not familiar with compiler switches, I only tried to use #pragma optimize("", on/off)
around the above functions, but that didn't help. Does somebody have an idea how to make Visual Studio to compile my code?
Remark: I am pretty sure that the struct B
is not important here, in my case, it is a simple data struct containing some built-in variables.
Upvotes: 1
Views: 599
Reputation: 302718
First, an internal compiler error is always a compiler bug. Please report this to MSVC.
Second, this implementation is a bit odd. When you write constexpr
functions you want to think in a more functionally-oriented way - input-only arguments, output-only results. count_in_array
should surely just return a number:
template <size_t Size>
constexpr uint32_t count_in_array(B b, const std::array<B, Size>& a)
{
uint32_t count = 0;
for(auto& e : a)
{
if(e==b)
++count;
}
return count;
}
This is a more reasonable implementation - count
returns a count. Not only that, but it composes really nicely. How do you get all the counts? You sum them:
template <size_t... Ids>
constexpr uint32_t count_in_arrays(B b, std::index_sequence<Ids...>)
{
return (count_in_array(b, A<Ids>::member) + ...);
}
Much clearer.
Note that, while I think fold-expressions don't quite work in MSVC yet (though might soon?), that in of itself is not a reason to implement this differently. It just means that you need to manually sum - not that count_in_array()
shouldn't return a count.
Upvotes: 1