Adding informational messages

As you test and debug code you will inevitably come across places where you can see a potential problem but it has low priority compared to what you are working on. It is important to make a note of the issue so that you can address the problem at a later stage. In Visual C++, there are two ways to do this in a benign way and two ways that will generate an error.

The first way is to add a TODO: comment, shown as follows:

    // TODO: potential data loss, review use of shift8 function 
unsigned shift8(unsigned char c)
{
return c >> 8;
}

The Visual Studio editor has a tool window called the Task List. This lists the comments in the project that start with one of the predetermined tasks (the defaults are TODO, HACK, and UNDONE).

If the Task List window is not visible, enable it via the View menu. The default setting in Visual Studio 2015 is to enable tasks in C++. This is not the case for earlier versions, but it can be enabled through the Tools menu, Options dialog and then Text Editor, C/C++, Formatting, View by setting Enumerate Comment Tasks to Yes. The list of task labels can be found on the Options dialog under the Environment, Task List item.

The Task List lists the tasks with the file and line number, and you can open the file and locate the comment by double-clicking on an entry.

The second way to identify code that needs attention is the message pragma. As the name suggests, this simply allows you to place an informational message in your code. When the compiler comes across this pragma it simply puts the message on the output stream. Consider the following code:

    #pragma message("review use of shift8 function") 
unsigned shift8(unsigned char c)
{
return c >> 8;
}

If the test.cpp file is compiled with this code and /W1 (the default) warning level, the output will be something like this:

    Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x86
Copyright (C) Microsoft Corporation. All rights reserved.

test.cpp
review the use of shift8 function
test.cpp(8): warning C4333: '>>': right shift by too large amount, data loss

As you can see, the string is printed just as the compiler sees it, and there is no indication of the file or line number in contrast to the warning message. There are ways to address this using compiler symbols.

If the condition is important, you'll want to issue an error and one way to do this is with the #error directive. When the compiler reaches this directive, it will issue an error. This is a serious action, so you will only use it when there is another option. You'll most likely want to use it with a conditional compilation. A typical use is for code that can only be compiled with a C++ compiler:

    #ifndef __cplusplus 
#error C++ compiler required.
#endif

If you compile a file with this code using the /Tc switch to compile code as C then the __cplusplus preprocessor symbol will not be defined and an error will be generated.

C++11 adds a new directive called static_assert. This is called like a function (and calls are terminated with a semicolon), but it is not a function because it is only used at compile time. Further, the directive can be used in places where function calls are not used. The directive has two parameters: an expression and a string literal. If the expression is false then the string literal will be outputted at compile time with the source file and line number and an error will be generated. At the simplest level, you could use this to issue a message:

    #ifndef __cplusplus 
static_assert(false, "Compile with /TP");
#endif
#include <iostream> // needs the C++ compiler

Since the first parameter is false, the directive will issue the error message during compilation. The same thing could be achieved with the #error directive. The <type_traits> library has various predicates for testing the properties of types. For example, the is_class template class has a simple template parameter that is a type, and if the type is a class then the static member value is set to true. If you have a templated function that should only be instantiated for classes, you could add this static_assert:

    #include <type_traits> 

template <class T>
void func(T& value)
{
static_assert(std::is_class<T>::value, "T must be a class");
// other code
}

At compile time, the compiler will attempt to instantiate the function and instantiate is_class on that type using value to determine if the compilation should continue. For example, the following code:

    func(string("hello")); 
func("hello");

The first line will compile correctly because the compiler will instantiate a function, func<string>, and the parameter is a class. However, the second line will not compile because the function instantiated is func<const char*> and const char* is not a class. The output is:

Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x86
Copyright (C) Microsoft Corporation. All rights reserved.

test.cpp
test.cpp(25): error C2338: T must be a class
test.cpp(39): note: see reference to function template instantiation

'void func<const char*>(T)' being compiled

with
[
T=const char *
]

The static_assert is on line 25, and hence this generates the error that T must be a class. Line 39 is the first call to func<const char*> and gives context to the error.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset