Geraldine Jones
Geraldine Jones

Reputation: 89

Assignment operators

The following expression is valid in C++:

A = B = C = 10;

The variables A, B, and C will now contain the value 10.

I'm trying to figure out how to make it so A, B, and C can contain the value of 10 when declared, not assign them later;

#include <iostream>
using namespace std;

int main()
{
   int A, B, C, = 10;
   int result;
   result = A = B = C = 10;
   cout << A << B << C << 10;

   result 0;
}

Upvotes: 7

Views: 279

Answers (7)

Adrian Mole
Adrian Mole

Reputation: 51815

If you really want to maintain your A = B = C = 10; syntax, then you can actually do this in a single-line declaration/initializer, provided you declare B and C before A. So:

int C, B, A = B = C = 10;

This is perfectly legal, and well-defined code. But I'm not saying it's what you should do. (Comments welcome giving examples of where such a form may be useful!)

Upvotes: 1

bolov
bolov

Reputation: 75668

I recommend the universally understood and used: int a = 10, b = 10, c = 10;

That being said...


C++17 !!!

We have Structured bindings so Yeey!!!

auto [a, b, c] = {10, 10, 10};

Oh, you can't do that? Oh well...


C++17

auto [a, b, c] = std::tuple{10, 10, 10};

C++20 !!!

We have Designated initializers Yeey!!

auto [a, b, c] = std::tuple{[0 ... 2] = 10};

auto [a, b, c] = (int[]){[0 ... 2] = 10};

Oh, you can't do that? Oh well...


At last the glorious solution

Okey... let's do it by hand. yey? :(

auto test()
{
    auto [a, b, c] = make_repeating_tuple<3, 10>();

    // or, alternative
    auto [a, b, c] = make_repeating_tuple<3>(10);
}

Implementation

#include <tuple>
#include <utility>
#include <type_traits>

namespace details
{
template <auto Val, std::size_t... Is>
constexpr auto make_repeating_tuple_impl(std::index_sequence<Is...>)
{
    // black magic
    return std::tuple{[] (auto) { return Val; }(Is)...};
}
}

template <int N, auto Val>
constexpr auto make_repeating_tuple()
{
    return details::make_repeating_tuple_impl<Val>(std::make_index_sequence<N>{});
}

Implementation (alternative)

namespace details
{
template <class T, std::size_t... Is>
constexpr auto make_repeating_tuple_impl(T val, std::index_sequence<Is...>)
{
    static_assert(std::is_trivially_copy_constructible_v<decltype(Val)>); // because

    // black magic
    return std::tuple{[=] (auto) { return val; }(Is)...};
}
}

template <int N, class T>
constexpr auto make_repeating_tuple(T val)
{
    return details::make_repeating_tuple_impl(val, std::make_index_sequence<N>{});
}

Burn The Witch! Burn The Witch!! Burn The Witch!!!

auto test()
{
    DECL_CHAIN_ASSIGN(10, a, b, c);
}

Implementation:

// the darkest of magics
#define DECL_CHAIN_ASSIGN(val, ...) \
    auto [__VA_ARGS__] = make_repeating_tuple<PP_NARG(__VA_ARGS__)>(val)

With

#define PP_NARG(...) \
         PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) \
         PP_ARG_N(__VA_ARGS__)
#define PP_ARG_N( \
          _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
         _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
         _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
         _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
         _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
         _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
         _61,_62,_63,N,...) N
#define PP_RSEQ_N() \
         63,62,61,60,                   \
         59,58,57,56,55,54,53,52,51,50, \
         49,48,47,46,45,44,43,42,41,40, \
         39,38,37,36,35,34,33,32,31,30, \
         29,28,27,26,25,24,23,22,21,20, \
         19,18,17,16,15,14,13,12,11,10, \
         9,8,7,6,5,4,3,2,1,0
// taken from
// https://stackoverflow.com/questions/2124339/c-preprocessor-va-args-number-of-arguments

On a more serious note: Don't use the macro!!

Upvotes: 2

Dmitry Kuzminov
Dmitry Kuzminov

Reputation: 6584

Declaration differs from assignment a lot. Usually assignment operator returns the reference to the object. For example the type of this operation is int&:

int a;
a = 10;

This allows you chaining the assignments like that: a = b = c = 10: at the end of the day the type of this operator is int& again and you still can add one more assignment to the right.

The definition of the variables is another story. Each variable has to get it's own value (or no value at all), but there is no way to "assign" (actually initialize) a single value "in one assignment".

However maybe this can solve your actual problem:

const int value = 10;
int a = value, b = value, c = value;

By the way, defining several variables in one line is a bad practice. Your example is one illustration of the problem. Other problems with that: what is the pointer, what is the reference and what is just a pure int in the next example?

int val;
int* a, b;
int& c = val, d = val;

Upvotes: 3

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 122133

You cannot do what you want directly. However, in my opinion wanting to initialize them with the same value is reason enough to define a class:

struct ABC {
    int A,B,C;
    ABC(int x) : A(x),B(x),C(x) {}
};

If there is a relation between A,B and C, make it explicit. Now you can use a single value to initialize them:

ABC abc{10};

Upvotes: 4

NathanOliver
NathanOliver

Reputation: 180415

In C++ every variable definition has to have its own initializer. If you want to chain that then you need to use something like

int A = 10, B = A, C = B;

This will do what you want but it is required to you manually specify the initializer.

Upvotes: 6

Marshall Clow
Marshall Clow

Reputation: 16670

You can certainly write: int a = 10, b = 10, c = 10;

Upvotes: 3

Remy Lebeau
Remy Lebeau

Reputation: 595320

C++ does not work that way. Although you can declare multiple variables of the same type in a single statement, you can't initialize them with a single value, they must be initialized individually, eg

int A = 10, B = 10, C = 10;

So, what you are trying to do only works in assignments, not in declarations.

Upvotes: 1

Related Questions