Declaring a variable with two types: "int char"

C++Type ConversionInitializationUniform InitializationNarrowing

C++ Problem Overview


I'm a C++ beginner, and I'm reading Bjarne Stroustrup's Programming: Principles and Practice Using C++.

In the section on 3.9.2 Unsafe conversions, the author mentioned

> When the initializer is an integer literal, the compiler can check the actual value and accept values that do not imply narrowing: > > int char b1 {1000}; // error: narrowing (assuming 8-bit chars)

I'm puzzled by this declaration. It uses two types (int and char). I have never seen such declaration in Java and Swift before (the two languages I'm relatively familiar with). Is this a typo or a valid C++ syntax?

C++ Solutions


Solution 1 - C++

It's a mistake in the book. That is not a valid C++ declaration, even without the supposed narrowing conversion.

It isn't mentioned in any of the erratas on Bjarne Stroustrup's page(4th printing and earlier), though, which is odd. It's a clear enough mistake. I imagine since it's commented with //error few people notice the mistake in the declaration itself.

Solution 2 - C++

The book is wrong.

The token sequence int char b1{1000}; is not semantically valid C++.

You are trying to declare b1 with more than one type, which makes no sense.

Solution 3 - C++

It is wrong. In C/C++ the multi-type declarations can be achieved via the use of unions. Eg:

union {
    int i;
    char c;
} var;

var.i = 42;
/* OR */
var.c = ‘c’;

The storage is the same, so .c and .i are just per-type handles to the same value.

Solution 4 - C++

This is wrong in C/C++ syntax. In addition to unions (see @Alex answer), there is a C++ way to store only one of available types called std::variant (type-safe union):

#include <variant>
#include <string>
 
int main()
{
    std::variant<int, float> v, w;
    v = 12; // v contains int
    int i = std::get<int>(v);
    w = std::get<int>(v);
    w = std::get<0>(v); // same effect as the previous line
    w = v; // same effect as the previous line
 
//  std::get<double>(v); // error: no double in [int, float]
//  std::get<3>(v);      // error: valid index values are 0 and 1

    try {
      std::get<float>(w); // w contains int, not float: will throw
    }
    catch (std::bad_variant_access&) {}
 
    std::variant<std::string> v("abc"); // converting constructors work when unambiguous
    v = "def"; // converting assignment also works when unambiguous
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionThorView Question on Stackoverflow
Solution 1 - C++StoryTeller - Unslander MonicaView Answer on Stackoverflow
Solution 2 - C++BathshebaView Answer on Stackoverflow
Solution 3 - C++AlexView Answer on Stackoverflow
Solution 4 - C++val is still with MonicaView Answer on Stackoverflow