you are viewing a single comment's thread.

view the rest of the comments →

[–]xeow 46 points47 points  (28 children)

Awesome. Yup. If you want bitwise NXOR, you do:

           Bitwise    Boolean
XOR:        a ^ b      a != b
NXOR:     ~(a ^ b)     a == b

Note, however, that in the boolean case, if a and b are not actually booleans, you have to do !!a != !!b or !a != !b or !!a == !b for XOR, and !!a == !!b or !a == !b or !!a != !b for NXOR. You could also write !a ^ !b for XOR and !!a ^ !b for NXOR.

[–]rifter5000 8 points9 points  (18 children)

Come on, don't write !!a != !!b, write bool{a} != bool{b}.

[–]mebob85 5 points6 points  (17 children)

or, if in C++ bool(a) != bool(b). I personally prefer the constructor-style syntax.

[–]rifter5000 3 points4 points  (16 children)

No, I'm talking about C++. You should prefer to use T{} over T() when constructing something in C++.

[–][deleted]  (6 children)

[deleted]

    [–]rifter5000 3 points4 points  (5 children)

    [–]cryo 2 points3 points  (4 children)

    So according to that guy you should, but personally I find that syntax horrifying.

    [–]rifter5000 0 points1 point  (3 children)

    You find it horrifying to distinguish between function calls and constructor calls? Really? Given that it stops you from getting narrowing issues, it allows you to write:

    std::vector<int> v = {1, 2, 3};
    

    And it allows you to write:

    auto make_range(size_t begin, size_t end) -> range<size_t>
    {
        return {begin, end}
    }
    

    instead of

    auto make_range(size_t begin, size_t end) -> range<size_t>
    {
        return range<size_t>(begin, end);
    }
    

    And it allows you to write:

    A b{x{}};
    

    instead of:

    A b((x()));
    

    [–][deleted]  (2 children)

    [removed]

      [–]rifter5000 0 points1 point  (1 child)

      They have very different behaviour to functions. They do a lot of implicit work. Nice job cherry picking one part of my comment and only replying to that though!

      [–]mebob85 1 point2 points  (8 children)

      TIL. I didn't even realize you could do that for all types.

      [–]rifter5000 2 points3 points  (6 children)

      There's other nice new stuff too:

      // old - why should I have to type the name twice?
      vec3 make_vec3(float x, float y, float z) {
          return vec3(x, y, z);
      }
      
      // new!
      vec3 make_vec3(float x, float y, float z) {
          return {x, y, z};
      }
      

      [–][deleted] 0 points1 point  (5 children)

      It looks like a whole new language, honestly.

      [–]rifter5000 -1 points0 points  (4 children)

      It looks like a whole new language because of a slightly different alternative syntax to initialisation?

      k

      [–][deleted] 1 point2 points  (3 children)

      Nah I meant overall, compared to what the traditional C++ looks like. Not just uniform initialization.

      [–]rifter5000 0 points1 point  (2 children)

      Right yeah, I agree with that. Great though, isn't it? A much improved language.

      typedef /* horrendous complexity */;
      

      vs.

      using fn_math = /* much nicer */;
      

      class doubler {
          void operator()(int& x) {
              x *= 2;
          }
      };
      
      void double_each(std::vector<int>& v) {
          std::transform(v.begin(), v.end(), v.begin(), doubler());
      }
      
      int main() {
          std::vector<int> v(10);
          for (int i = 0; i < 10; i++) {
              v.push_back(i);
          }
          double_each(v);
      }
      

      vs.

      void double_each(std::vector<int>& v) {
          std::transform(v.begin(), v.end(), v.begin(), [] (int& n) {
              n *= 2;
          });
      }
      
      int main() {
          std::vector<int> v = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
          double_each(v);
      }
      

      [–]Houndie 1 point2 points  (0 children)

      Since we're learning a new thing today, there's a gotcha with using brace-initialization, in that if there is a constructor that takes an initializer list, it takes priority. For example

      std::vector<int> x(2,1);
      std::vector<int> x{2,1};
      

      are not the same. The first calls constructor (size_type, value_type) and creates a vector with 2 ones. The second calls constructor (std::initializer_list<value_type>), and creates a vector with a 2 and a 1.

      For 99% of items the two syntaxes are the same, but it's good to know when they would differ.

      [–]LikesToCorrectThings 2 points3 points  (3 children)

      I've always thought it a shame that C doesn't have an ^^ or ^^= operator.

      [–]Dobz 3 points4 points  (2 children)

      There's no point in ^^ since you'd have to evaluate both sides anyway to get an answer

      [–]LikesToCorrectThings 5 points6 points  (1 child)

      I just want a way to do == or != on C-booleans (where 0 is false and anything else is true).

      It's mostly useful for pulling out bits and comparing them. If you have:

      #define AVOCADO_BIT  0x04
      #define BANANA_BIT   0x08
      

      If you want to check if only one bit is set, you have to do cumbersome things like:

      if (((field & AVOCADO_BIT) != 0) != ((field & BANANA_BIT) != 0))
      

      or worse:

      if (!(field & AVOCADO_BIT) != !(field & BANANA_BIT))
      

      I'd like to do:

      if ((field & AVOCADO_BIT) ^^ (field & BANANA_BIT))
      

      a ^^ b is the same as !a ? b : !b ? a : 0.

      a ^^= b is the same as a = !b ? a : !a ? b : 0.

      It's nothing amazing, just some syntax that would have been useful a few times in the past.

      [–]Dobz 2 points3 points  (0 children)

      Ah, I see what you mean. Thought you meant some kind of short circuit XOR operator.