error: no member named 'rank_' in 'EndIndex' - c++

I am trying to use the automatic differentiation library Adept and I made it work with gcc 4.9.0 and icc 16.0.2 but failed with VS 2017 and Clang 4.0.1
I have reduced the problem to the following snippet and, while I am addressing the issue with the library creators, for the sake of the knowledge I would like to know why this piece of code works in the two mentioned compilers and fails to build in the other two.
template <typename A>
struct Expression
{
static const int rank = A::rank_;
};
struct EndIndex : public Expression<EndIndex>
{
static const int rank_ = 0;
};
int main(int argc, char ** argv)
{
return 0;
}
Output for VS 2017 is:
1>------ Build started: Project: Test, Configuration: Debug Win32 ------
1>Source.cpp
1>d:\Test\source.cpp(4): error C2039: 'rank_': is not a member of 'EndIndex'
1>d:\Test\source.cpp(7): note: see declaration of 'EndIndex'
1>d:\Test\source.cpp(8): note: see reference to class template instantiation 'Expression<EndIndex>' being compiled
1>d:\Test\source.cpp(4): error C2065: 'rank_': undeclared identifier
1>d:\Test\source.cpp(4): error C2131: expression did not evaluate to a constant
1>d:\Test\source.cpp(4): note: failure was caused by non-constant arguments or reference to a non-constant symbol
1>d:\Test\source.cpp(4): note: see usage of 'rank_'
1>Done building project "Test.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
And output for Clang 4.0.1:
source.cpp:4:37: error: no member named 'rank_' in 'EndIndex'
static const int rank = A::rank_;
~~~^
source.cpp:7:38: note: in instantiation of template class 'Expression<EndIndex>' requested here
struct EndIndex : public Expression<EndIndex>

It probably happens because rank_ is not defined at that stage.
The following fixes it for Apple LLVM version 9.0.0 (clang-900.0.38):
template <typename A>
struct Expression
{
static const int rank;
};
struct EndIndex : public Expression<EndIndex>
{
static const int rank_ = 0;
};
template <typename A>
const int Expression<A>::rank = A::rank_;

Visual C++ and clang are simply unable to find rank_ member of EndIndex because it's being accessed before declared. Such fancy code often leads to problems in some environments.

Related

c++ boost 1.71 compile error C2061 syntax error: identifier 'L'

I recently upgraded to Boost 1.71 x64-windows via vcpkg. On a Visual Studio 2017 project that compiled perfectly before the upgrade, I'm now getting this error:
2> \x64-windows\include\boost\test\tools\floating_point_comparison.hpp(60): error C2061: syntax error: identifier 'L'
2> \x64-windows\include\boost\test\tools\floating_point_comparison.hpp(68): note: see reference to class template instantiation 'boost::math::fpc::is_abstract_class_or_function<T>' being compiled
2> \x64-windows\include\boost\log\utility\formatting_ostream.hpp(562): note: see reference to function template instantiation 'boost::log::v2_mt_nt6::basic_formatting_ostream<char,std::char_traits<CharT>,std::allocator<char>> &boost::log::v2_mt_nt6::basic_formatting_ostream<CharT,std::char_traits<CharT>,std::allocator<char>>::formatted_write<_Elem>(const OtherCharT *,std::streamsize)' being compiled
Not sure if the problem is in Boost::Log or Boost::Test. Here's the offending code in floating_point_comparison.hpp:
template<typename T>
class is_abstract_class_or_function
{
typedef char (&Two)[2];
template<typename U> static char test(U(*)[1]); // <- ***
template<typename U> static Two test(...);
public:
static const bool value =
!is_reference<T>::value
&& !is_void<T>::value
&& (sizeof(test<T>(0)) == sizeof(Two));
};
There are no errors in the output that pertain to my code. In fact, I removed all my .cpp source files from the project (just left the header files) and still got the compile error.
You have a macro somewhere, which is something like: #define U(str) L##str.
So U(*) gets turned into L*, but U doesn't get turned into L.

Dispatch template <auto>

I try to dispatch between two functions using if constexpr. The dispatcher function should accept for example std::size_t and an arbitrary class type.
It works if I just call it with a scalar type, but if I try to pass a class type it triggers a compile error which is not really helpful to me (please see below).
Please have a look at my current approach:
template <auto Other>
constexpr auto mul() const {
if constexpr (std::is_scalar_v<decltype(Other)>)
return mul_with_scalar<Other>();
else
return mul_with_matrix<Other>();
}
template <size_t Scalar>
constexpr auto mul_with_scalar() const {
return apply([](size_t v, auto) { return v * Scalar; },
std::make_index_sequence<Size>{});
}
template <class Other>
constexpr auto mul_with_matrix() const {
return size_t{0}; // implement me
}
note: candidate: template<auto Other> constexpr auto matrix<Rows, Cols, Vals>::mul() const [with auto Other = Other; long unsigned int Rows = 3; long unsigned int Cols = 3; long unsigned int ...Vals = {}]
constexpr auto mul() const {
^~~
./constexpresian/matrix.hpp:81:18: note: template argument deduction/substitution failed:
I wan't that the function mul can handle non-type and type parameters.
That is not possible in C++. A template parameter can be a type or a value (or a template), but it cannot be both. template<auto Name> makes Name a value template parameter, the type of whose value will be deduced at the time the value is passed.
But since it is a compile-time value, you can wrap its value in a type. For integer types, std::integer_constant will work. For future C++ revisions that allow other kinds of value parameters, you'll have to use a more generic wrapper.
There is one question I have, you can refer to my comment below your post that pertains to the term Size.
I tried your code above as is even with Size the way it is to see the compiler errors and this is coming from Visual Studio 2017 v4.6.0105 c++17 on Win 7 x64 Home Premium under x86 Debug on an Intel Quad Core Extreme.
1>------ Build started: Project: StackOverflow, Configuration: Debug Win32 ------
1>Learner.cpp
1>c:\users\skilz80\documents\visual studio 2017\projects\stackoverflow\stackoverflow\learner.h(75): error C3533: a parameter cannot have a type that contains 'auto'
1>c:\users\skilz80\documents\visual studio 2017\projects\stackoverflow\stackoverflow\learner.h(75): error C2270: 'mul': modifiers not allowed on nonmember functions
1>c:\users\skilz80\documents\visual studio 2017\projects\stackoverflow\stackoverflow\learner.h(83): error C2270: 'mul_with_scalar': modifiers not allowed on nonmember functions
1>c:\users\skilz80\documents\visual studio 2017\projects\stackoverflow\stackoverflow\learner.h(89): error C2270: 'mul_with_matrix': modifiers not allowed on nonmember functions
1>Done building project "StackOverflow.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Maybe this interpretation of these compiler errors might help you.
Here are some links that might help concerning auto and template parameters:
StackOverflow : Advantages of auto in template parameters in C++17
open-std.org : Declaring non-type template arguments with auto
www.bfilipek.com : C++17 in details: Templates

How to specify OpenMP execution policy in cuda thrust calls on Windows?

While porting a code from Linux to Windows, thanks to Visual Studio C++ 2015 Community, I encountered a compilation error that I cannot understand.
Below is a sample program exhibiting this error, building a vector of doubles and then sorting it with cuda thrust, using OpenMP.
# include <thrust/sort.h>
# include <thrust/system/omp/execution_policy.h>
# include <chrono>
# include <random>
# include <vector>
double unit_random()
{
static std::default_random_engine generator(std::chrono::system_clock::now().time_since_epoch().count());
static std::uniform_real_distribution<double> distribution(double(0), double(1));
return distribution(generator);
}
int main(int argc, char* argv[])
{
constexpr size_t input_size = 100000;
std::vector< double > input(input_size, 0);
for ( size_t i = 0; i < input_size; ++i)
input[i] = unit_random() * 1000;
thrust::sort(thrust::omp::par, input.begin(), input.end());
return 0;
}
Here is the error seen in the Visual Studio console (file names are shortened):
thrust/system/omp/detail/sort.inl(136): error C2146: syntax error: missing ';' before identifier 'nseg'
thrust/detail/sort.inl(83): note: see reference to function template instantiation 'void thrust::system::omp::detail::stable_sort<thrust::system::omp::detail::par_t,RandomAccessIterator,StrictWeakOrdering>(thrust::system::omp::detail::execution_policy<thrust::system::omp::detail::par_t> &,RandomAccessIterator,RandomAccessIterator,StrictWeakOrdering)' being compiled
with
[
RandomAccessIterator=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>,
StrictWeakOrdering=thrust::less<value_type>
]
thrust/system/detail/generic/sort.inl(63): note: see reference to function template instantiation 'void thrust::stable_sort<DerivedPolicy,RandomAccessIterator,StrictWeakOrdering>(const thrust::detail::execution_policy_base<DerivedPolicy> &,RandomAccessIterator,RandomAccessIterator,StrictWeakOrdering)' being compiled
with
[
DerivedPolicy=thrust::system::omp::detail::par_t,
RandomAccessIterator=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>,
StrictWeakOrdering=thrust::less<value_type>
]
thrust/detail/sort.inl(56): note: see reference to function template instantiation 'void thrust::system::detail::generic::sort<Derived,RandomAccessIterator,StrictWeakOrdering>(thrust::execution_policy<Derived> &,RandomAccessIterator,RandomAccessIterator,StrictWeakOrdering)' being compiled
with
[
Derived=thrust::system::omp::detail::par_t,
RandomAccessIterator=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>,
StrictWeakOrdering=thrust::less<value_type>
]
thrust/system/detail/generic/sort.inl(49): note: see reference to function template instantiation 'void thrust::sort<DerivedPolicy,RandomAccessIterator,thrust::less<value_type>>(const thrust::detail::execution_policy_base<DerivedPolicy> &,RandomAccessIterator,RandomAccessIterator,StrictWeakOrdering)' being compiled
with
[
DerivedPolicy=thrust::system::omp::detail::par_t,
RandomAccessIterator=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>,
StrictWeakOrdering=thrust::less<value_type>
]
thrust/detail/sort.inl(41): note: see reference to function template instantiation 'void thrust::system::detail::generic::sort<Derived,RandomAccessIterator>(thrust::execution_policy<Derived> &,RandomAccessIterator,RandomAccessIterator)' being compiled
with
[
Derived=thrust::system::omp::detail::par_t,
RandomAccessIterator=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>
]
windows_cuda_thrust_error.cc(24): note: see reference to function template instantiation 'void thrust::sort<DerivedPolicy,std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>>(const thrust::detail::execution_policy_base<DerivedPolicy> &,RandomAccessIterator,RandomAccessIterator)' being compiled
with
[
DerivedPolicy=thrust::system::omp::detail::par_t,
RandomAccessIterator=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>
]
thrust/system/omp/detail/sort.inl(136): error C2275: 'IndexType': illegal use of this type as an expression
thrust/system/omp/detail/sort.inl(113): note: see declaration of 'IndexType'
thrust/system/omp/detail/sort.inl(136): error C2065: 'nseg': undeclared identifier
thrust/system/omp/detail/sort.inl(142): error C2065: 'nseg': undeclared identifier
thrust/system/omp/detail/sort.inl(159): error C2065: 'nseg': undeclared identifier
========== Build: 0 succeeded, 1 failed, 1 up-to-date, 0 skipped ==========
The same code works fine on Linux.
How are we supposed to specify an OpenMP execution policy in a cuda thrust call on Windows? Alternatively, what I am doing wrong in this particular context?
The thrust version used is 1.8.1 and here is an excerpt of the thrust function, in file thrust/system/omp/detail/sort.inl, raising the compilation errors:
template<typename DerivedPolicy,
typename RandomAccessIterator,
typename StrictWeakOrdering>
void stable_sort(execution_policy<DerivedPolicy> &exec,
RandomAccessIterator first,
RandomAccessIterator last,
StrictWeakOrdering comp)
{
// ...
typedef typename thrust::iterator_difference<RandomAccessIterator>::type IndexType;
if(first == last)
return;
#pragma omp parallel
{
thrust::system::detail::internal::uniform_decomposition<IndexType> decomp(last - first, 1, omp_get_num_threads());
// process id
IndexType p_i = omp_get_thread_num();
// every thread sorts its own tile
if(p_i < decomp.size())
{
thrust::stable_sort(thrust::seq,
first + decomp[p_i].begin(),
first + decomp[p_i].end(),
comp);
}
#pragma omp barrier
IndexType nseg = decomp.size(); // line 136
// ...
}
}
As suggested by #kangshiyin, I filed an issue on github (see issue #817) and thrust developers found a workaround. The problem came from the way MSVC currently deals with OpenMP code, so the code provided in the question was perfectly fine.
If a similar problem arise, try first to update to the latest version of thrust. You can also try to apply the same workaround: simply add a semi-colon before the line raising the error.

Error while compiling in gcc

I am doing a project for my class where the instructor had given us some code snippets and we were asked to modify it. The code compiles correctly in my class computer in Visual Studio but when I try to compile it with gcc it gives me an error.
The error I am getting is:
||=== Build: Debug in Project (compiler: GNU GCC Compiler) ===|
/home/nitin/Read.h|45|error: declaration of ‘std::vector<rv> rvs::rv’ [-fpermissive]|
/home/nitin/Read.h|35|error: changes meaning of ‘rv’ from ‘struct rv’ [-fpermissive]|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
The code from the error is snippet for this is:
struct rv
{
double val, prob;
rv(const double v, const double p): val(v), prob(p) {};
};
struct rvs
{
int row_n, col_n;
vector<rv> rv;
rvs(const int r=-2, const int c=-2): row_n(r), col_n(c) {};
};
Could you please let me know what the problem could be?
Your declarations violate the following rule
3.3.7 Class scope [basic.scope.class]
1 The following rules describe the scope of names declared in classes.
...
2) A name N used in a
class S shall refer to the same declaration in its context and when
re-evaluated in the completed scope of S. No diagnostic is required
for a violation of this rule.
At the point of vector declaration name rv refers to a type struct rv. But when reevaluated in the scope of complete class rvs it, refers to class member rvs::rv. Such inconsistency is an error in C++.
A similar error is illustrated by an example in the standard
enum { i = 1 };
class X {
char v[i]; // error: i refers to ::i
// but when reevaluated is X::i
...
enum { i = 2 };
};
As #Ben Voigt stated in the comment, if you explicitly resolve the conflict between rv as struct rv and rv as rvs::rv, the error will go away. You can do it by either using elaborate type specifier struct rv or by specifying scope explicitly ::rv.
Note that this is one of those errors which are not guaranteed/required to be caught by the compiler.
You have a type called rv and a member variable called rv. How is the compiler supposed to know which one you mean when you write rv?
Strictly this is invalid code, but Visual Studio seems to be willing to try to let you shoot yourself in the foot.

Pointer to member, within class

I am trying create a typedef for a template that needs a pointer to member, from within a class. The best way to describe it is to show the minimal sample code:
template<typename T, int T::*MV>
struct Bar
{
const int &value(const T &t) const
{
return (t.*MV);
}
};
struct Foo
{
int baz;
typedef Bar<Foo, &Foo::baz> GetBaz; // Compiler error
};
typedef Bar<Foo, &Foo::baz> GetFooBaz; // Compiles just fine
int main(int argc, char* argv[])
{
Foo f = { 42 };
Foo::GetBaz b; // Fails to compile
GetFooBaz b2; // Fine
int val = b.value(f); // Fails to compile because of above
int val2 = b2.value(f); // Fine
}
I am not necessarily dead-set on getting access to a member pointer in this way, I would be fine just knowing the offset to the variable and having the Bar::value function perform trickery.
As a last resort, I suppose I could use a traits class since the would move the definition outside of the class, but I would prefer to be able to declare the typedef near the variable being used.
And, to answer the "why would you want to do that" question, this is all for an IoC container that closely represents the way MEF (C# works).
The specific compiler I am using is VC12, but it would be nice if VC11 supported it as well.
Thanks
EDIT:
Here are the error messages
1>------ Build started: Project: MemVarBug, Configuration: Debug Win32 ------
1> MemVarBug.cpp
1>memvarbug.cpp(20): error C2327: 'Foo::baz' : is not a type name, static, or enumerator
1>memvarbug.cpp(20): error C2065: 'baz' : undeclared identifier
1>memvarbug.cpp(20): error C2975: 'MV' : invalid template argument for 'Bar', expected compile-time constant expression
1> memvarbug.cpp(7) : see declaration of 'MV'
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
you can do the following trick:
declare baz to be int[1];
array of size one, in this case calling baz will return the pointer and calling *baz will return the value.