wtorek, 29 lipca 2014

Undesirable implicit conversions

Recently Andrzej Krzemienski published a post on his blog about inadvertent conversions. Basically the problem is that sometimes compiler performs implicit conversions (and, as of C++ standard it is allowed to perform at most one) that aren't desired by programmers. In my post I'd like to summarize all solutions that I'm aware of with ones that appeared in comments.

Classical source of such undesirable conversions are non-explicit constructors accepting exactly one non-default parameter. However, in this example there's a need to disable particular converting constructors while still accepting desired ones. Consider following piece of code:

1 struct C {
2     C(int const n) {}
3 };
4 
5 int main(void) {
6     C fromInt = 5;      // Okay
7     C fromDouble = 5.5; // Potentially not desired
8 }

This kind of problem occurs in boost::rational library, as Andrzej mentions. Okay, so what are the solutions? The first one is pretty obvious - let's explicitly delete all constructors accepting double as parameter.

1 struct C {
2     C(int const n) {}
3     C(double const x) = delete;
4 };
5 
6 int main(void) {
7     C fromInt = 5;      // Okay
8     C fromDouble = 5.5; // Illegal!
9 }

The solution is pretty straightforward and it addresses the problem basing on type, not type traits - which can be a problem in some contexts. There is another solution that lacks this particular problem. It employs enable_if to make sure only integral types can be used with our converting constructors.

 1 #include <type_traits>
 2 using namespace std;
 3 
 4 struct C {
 5     template <typename T, typename enable_if<is_integral<T>::value, int>::type = 0>
 6     C(T const n) {}
 7 };
 8 
 9 int main(void) {
10     C fromInt = 5;      // Okay
11     C fromDouble = 4.0; // Illegal!
12 }

It is elegant and it does the job well. However, in my humble opinion there's one area of improvement - diagnostics and readability. If we used static_assert error message produces by the compiler would be a lot more readable to the programmer. Also, the code would become more clear and the intentions would be visible at first sight.

1 #include <type_traits>
 2 using namespace std;
 3 
 4 struct C {
 5     template <typename T>
 6     C(T const n) {
 7         static_assert(is_integral<T>::value, "Only integral values are supported!");
 8     }
 9 };
10 
11 int main(void) {
12     C fromInt = 5;
13 
14     // error: static_assert failed "Only integral values are supported!"
15     C fromDouble = 4.0;
16 }

Do you know any issues that can appear with last solution? If yes please share them in comments, please ;)

Interestingly, when you compile example from the first listing on Clang (3.5, trunk 196051) you'll get an warning that implicit conversion is being used. GCC (4.8.2) stays quiet about that. This is another proof that clang is more user-friendly compiler.




środa, 23 lipca 2014

Pointers to class members and their addresses

Today I was trying to help my work mate to design sort of unit testing helper. Basically it was about function pointers to virtual methods. Pointers to functions take virtuality into account when they are called with a reference or a pointer to the base class. The thing is that before I made my point, we have decided to check one simple thing.
So here's a puzzle for you. Given following code (and without using a compiler) try to answer following questions.

 1 #include <iostream>
 2 using namespace std;
 3 
 4 struct A {
 5     virtual void foo() {}
 6 };
 7 
 8 struct B : A {
 9     virtual void foo() {}
10 };
11 
12 int main(void) {
13     cout << hex << &A::foo << endl;
14     cout << hex << &B::foo << endl;
15 }

1. Will this code compile?
2. If yes, what will be the addresses of A::foo and B::foo methods, respectively?
3. If yes, what will be the output of this program?

Did you think about it? Remember... there's no hurry ;-).

Answer to the first question is positive as the code is well-formed C++. What about addresses of methods? C++ requires that every method has it's own unique place to live - an address (or offset). Virtuality does not change anything here, so we can assume that these addresses are some integers, let's say a and b.
The last question is the most tricky one. While intuition suggests that the output might look like following, it's not true at all.

  0x00c0d150
  0x00c0d15c

The real output of the program is:

  1
  1

What a surprise, right? The catch in above code fragment is that there's no overloaded function accepting function pointer for ostream. What the compiler can do instead? It can use implicit conversion. It turns out that there's implicit conversion from function pointer to a boolean. This would spill out if we used std::boolalpha flag, but who knew?

I'd like to ask you one more question: what if we used reinterpret_cast<void*> against member pointers in lines 13-14? Would the output have gotten right then?
Surprisingly, the code would not compile then. The reason for that are some machines that hold code and data memory in different locations. Therefore, it's hard to specify a portable way to convert between pointers to the data and pointers to the code.
The funny fact is that clang does not compile it, while GCC only issues a warning.


wtorek, 22 lipca 2014

Surprise of the week

There is no doubt that programmers are very creative creatures. The more lazy they are the more astonishing stuff they can create. This short post is just about a piece of code that I have found in some project. Before I step into details I'd like to provide you some background.

Everyone knows that C++ macros are evil. There are many techniques that can help avoid them, but in some situations it's just not worth to apply these techniques. Such a situation would be allowing mocks to unit test production code. I'm not going to discuss whether it is good or bad to use mocks, but they have one small flaw - when you want to use them you probably will have to make methods virtual.
And this is our problem here - how to make this happen only on test builds? We surely don't want our production code to use vtables just-because. This is where some ifdefs can actually save the day:

1 #ifdef UT
2 #  define MOCKABLE virtual
3 #else
4 #  define MOCKABLE
5 #endif
6 
7 struct MockableClass {
8     MOCKABLE happyMethod() const;
9 };

In above example happyMethod will be virtual only when UT flag is passed to the compiler. Thus, it can be mocked with GTest's StrictMock, for instance.

This is pretty straightforward. Also, if it is used correctly, side effects are not supposed to happen. So now, when you have some background please have a look at the following.

1 #ifdef UT
2 #  define CONST
3 #else
4 #  define CONST const
5 #endif
6 
7 struct WeirdClass {
8     void notReallyHappyMethod(Object CONST object);
9 };

This is not even similar thing. The object that is passed to the method is either constant or not - depending on build type. I can't imagine how many side effects this may have.

piątek, 18 lipca 2014

Multi-argument constructors with default parameters & explicit keyword

Recently I was reviewing some snippet of code. It looked similar to following.

1 struct S {
2     explicit S(int someParam, int otherParam = 0) {
3         // Implementation...
4     }
5 };

At a glance I spotted the explicit keyword and wondered if it's needed. It's obvious that for one-argument constructors it is needed, if we don't want compiler to perform implicit conversions. However, what is the behavior when there's more than one arguments, but with default values?

I dig into the C++ standard and found relevant example [N3242] § 12.3.1/1. In the example there's a constructor accepting const char* as the first argument and int as the second one. The second one has default value of 0.

So the rule is that any explicit multi-argument constructors may become implicit if they have all but one arguments with default values.