Why does scope of using directive make a difference? - c++

Below are two simplified code examples: the first one compiles just fine, the second one emits a compile error (no operator << found which takes a left hand operator ByteVector...).
The only difference in between the two examples is the placement of the using directive.
I don't want to know why it fails (you got not enough information to answer this), I am only interested in why it does make any difference where I place the using.
I would have expected the exact same behaviour in both examples.
Compiles without error
ByteVector Test()
{
using Base::operator <<;
ByteVector foo;
int bar = 1;
foo << bar;
return foo;
}
Compiles with error
using Base::operator <<;
ByteVector Test()
{
...same as above, without using
}
Extra information:
The operator<< used is defined as follows
template<typename T>
ByteVector& operator<<(ByteVector &, const T&){...};

The only thing that comes to my mind is Visual Studio. If that was the case, you may want to put the using directive right after the corresponding #include. As the remark on the page says:
Putt your using directive at the beginning of the source code file to
reduce the potential for unexpected behavior with IntelliSense.
Otherwise, it shouldn't make any difference.

Related

Getting "instantiation resulted in unexecpted type" with MSVC

In a library of mine, I have the following bit of code (snipped for brevity):
namespace memory {
namespace managed {
namespace detail {
template <typename T>
inline T get_scalar_range_attribute(
region_t region,
cudaMemRangeAttribute attribute)
{ /* snip */ }
} // namespace detail
struct region_t : public memory::region_t {
// snip
bool is_read_mostly() const
{
return detail::get_scalar_range_attribute<bool>(
*this, cudaMemRangeAttributeReadMostly);
}
// snip
}
} // namespace managed
} // namespace memory
Now, with GCC and Clang on Linux, this works fine. But with MSVC 16.8.4 on Windows, a user of mine gets:
error : template instantiation resulted in unexpected function type of "__nv_bool
(cuda::memory::managed::region_t, cudaMemRangeAttribute)" (the meaning of a name
may have changed since the template declaration -- the type of the template is "T
(cuda::memory::region_t, cudaMemRangeAttribute)"
I don't understand how an instantiation can result in something unexpected, ever. I also don't see how my "name hiding" of one class name with another should have any effect on the template instantiation.
(Credit goes to #Guillaume Racicot for most of this.)
The issue here is the timing of name lookup.
Other compiles, when encountering the template declaration, region_t, seem to look for previously-defined region_t's; find memory::region_t; and be ok with that. (Correct me if I'm wrong).
MSVC, however, performs the lookup twice: Once when encountering the declaration+definition, then again upon instantiation - with different contexts both times. So, the first time, it finds memory::region_t; and the second time it finds memory::managed::region_t. This is "unexpected"...
This behavior of MSVC is apparently due to its "permissive" compilation mode (which is enabled by default). This is a bit weird, seeing how it is less permissive in this case, but that's just how it is.

Global namespace scope operator on function definition

I am in the process of creating a C wrapper around a C++ library.
One common mistake to make while doing this is having a function declaration and definition that do not match for some reason (typo, renames, argument got added/removed, etc).
For example:
// enabledata.h
MDS_C_API const char* motek_mds_enable_data_get_enable_command_name();
// enabledata.cpp
const char* motek_mds_enable_data_enable_command_name() { ... }
The names do not match, but because of the lack of scope for these functions, it will not result in any compile errors, and will only show up much later down the line as a link error.
I want the compiler to help me find these errors by using the global scope operator like so:
const char* ::motek_mds_enable_data_get_disable_command_name() { ... }
This will now show up as a compile error if the function has not been declared yet, which is exactly what I want.
However, this does not work when the function returns a typedef:
int32_t ::motek_mds_enable_data_is_enabled(const Data* a_Data) { ... }
This will result in an attempt to use int32_t as a scope, which of course results in an error:
left of '::' must be a class/struct/union
Are there any ways to make this work? Better alternatives are also welcome of course.
I am currently using Visual Studio 2015 Update 2.
You can always parenthesize the declarator-id:
int32_t (::motek_mds_enable_data_is_enabled)(const Data* a_Data) { ... }
// ^ ^

Can't get warnings to work for header-only library

I'm creating an header-only library, and I would like to get warnings for it displayed during compilation. However, it seems that only warnings for the "main" project including the library get displayed, but not for the library itself.
Is there a way I can force the compiler to check for warnings in the included library?
// main.cpp
#include "MyHeaderOnlyLib.hpp"
int main() { ... }
// Compile
g++ ./main.cpp -Wall -Wextra -pedantic ...
// Warnings get displayed for main.cpp, but not for MyHeaderOnlyLib.hpp
I'm finding MyHeaderOnlyLib.hpp via a CMake script, using find_package. I've checked the command executed by CMake, and it's using -I, not -isystem.
I've tried both including the library with <...> (when it's in the /usr/include/ directory), or locally with "...".
I suppose that you have a template library and you are complaining about the lack of warnings from its compilation. Don't look for bad #include path, that would end up as an error. Unfortunately, without specialization (unless the templates are used by the .cpp), the compiler has no way to interpret the templates reliably, let alone produce sensible warnings. Consider this:
#include <vector>
template <class C>
struct T {
bool pub_x(const std::vector<int> &v, int i)
{
return v.size() < i;
}
bool pub_y(const std::vector<int> &v, int i)
{
return v.size() < i;
}
};
typedef T<int> Tint; // will not help
bool pub_z(const std::vector<int> &v, unsigned int i) // if signed, produces warning
{
return v.size() < i;
}
class WarningMachine {
WarningMachine() // note that this is private
{
//T<int>().pub_y(std::vector<int>(), 10); // to produce warning for the template
}
};
int main()
{
//Tint().pub_y(std::vector<int>(), 10); // to produce warning for the template
return 0;
}
You can try it out in codepad. Note that the pub_z will immediately produce signed / unsigned comparison warning when compiled, despite never being called. It is a whole different story for the templates, though. Even if T::pub_y is called, T::pub_x still passes unnoticed without a warning. This depends on a compiler implementation, some compilers perform more aggressive checking once all the information is available, other tend to be lazy. Note that neither T::pub_x or T::pub_y depend on the template argument.
The only way to do it reliably is to specialize the templates and call the functions. Note that the code which does that does not need to be accessible for that (such as in WarningMachine), making it a candidate to be optimized away (but that depends), and also meaning that the values passed to the functions may not need to be valid values as the code will never run (that will save you allocating arrays or preparing whatever data the functions may need).
On the other hand, since you will have to write a lot of code to really check all the functions, you may as well pass valid data and check for result correctness and make it useful, instead of likely confusing the hell of anyone who reads the code after you (as is likely in the above case).

Compiler Robustness ... Naivete

I use Visual Studio Professional 2012. I pre-compiled a class (header and source) successfully. Days later, when compiling another class (for the moment header only) that is utilizing the previous one, the compiler caught a missing reference if(this != &rhs) and semicolon rhs.root = nullptr;.
Perhaps it is my naivete and lack of knowledge about how compilers work but I thought a compiler was robust to catch errors such as these. It appeared to me that only when a specific block of code was required did the compiler feel the need to check it.
I have read about just-in-time compilation and learned how assembly compilers perform a two-pass compilation with symbols first and then syntax. I have not taken a course in compiler construction at my university and I know such courses give great insight into parsers, etc.
The code section where it failed to catch the error is this move assignment operator:
Tree &operator=(Tree &&rhs)
{
if(this != rhs) <--------- no reference to the rhs
{
root = std::move(rhs.root);
rhs.root = nullptr <----------- no semicoln
}
return *this;
}
The errors were generated while compiling boost variant, as well as my visitor class member:
bool operator() (Tree<std::string>& tree) const {
return tree.load(tree);
}
as well as a host of other errors related to boost serialization. The fix was to, of course, correct the missing reference and semicolon but I want to understand why this was caught apparently only when the compiler needed to touch this code?
Is it a template class?
Because semantic analysis of templates makes only sense when they are instantiated. That is, if it is a template, the compiler should generate an error at the missing semicolon (syntactic error), but not at the == operator.
The following code compiles with g++:
template<typename T>
struct A {
void q(A &a) {
if (this == a) {}
}
};
int main(int argc, char **argv) {
A<int> x;
//x.q(x);
}
But doesn't compile when
x.q(x);
is uncommented.

Error C2275 caused by template member function. Is this code wrong?

I think I've run into a (possible) VC6 (I know. It's what we use.) compiler error, but am open to the fact that I've just missed something dumb. Given the following code (It's just an example!):
#include <iostream>
// Class with template member function:
class SomeClass
{
public:
SomeClass() {};
template<class T>
T getItem()
{
return T();
};
};
// Dummy just used to recreate compiler error
class OtherClass
{
public:
OtherClass() {};
};
std::ostream& operator<<( std::ostream& oStr, const OtherClass& obj )
{
return oStr << "OtherClass!";
};
// Main illustrates the error:
int main(int argc, char* argv[])
{
SomeClass a;
OtherClass inst2 = a.getItem<OtherClass>(); // Error C2275 happens here!
std::cout << inst2 << std::endl;
return 0;
}
If I try to compile this code VC6, dies on a.getItem<OtherClass>() yielding:
Error C2275: 'OtherClass' : illegal use of this type as an expression.
Have I overlooked some trivial syntax issue? Am I breaking a rule?
This code compiles just fine under gcc 4.3.4. Is it yet another compliance issue with VC6?
Thanks!
Among many other things with the word template in it, VC6 couldn't deal with function templates where the template parameters aren't also function parameters. The common workaround was to add a dummy function parameter:
template<class T>
T getItem(T* /*dummy*/ = NULL)
{
return T();
} // note: no ; after function definitions
However, in general, VC6 is pretty lame and often chokes as soon as a TU contains the template keyword. I had to beat my head against it for several years (big code base compiled with several compilers/compiler versions; VC6 giving us an endless amount of trouble) and was very glad when I got rid of it in 2003.
This is likely to be a VC6 issue. Although VC6 compiles most basic templates correctly it is known to have many issues when you start to move towards the more advanced template uses. Member templates are an area where VC6 is known to be weak on conformance.
I believe that's another bug in VC6, you should really switch to a more up-to-date compiler.