Ternary operator + C++11 constructor from initializer_list

泄露秘密 提交于 2021-02-16 05:39:11

问题


While developing an application, I had the following problem. I wanted to return an empty std::list<string> when a given function pointer was null, or the result of that function otherwise. This is a simplified version of my code:

typedef std::list<std::string> (*ParamGenerator)();

std::list<std::string> foo() {
    /* ... */
    ParamGenerator generator = ...;
    if(generator)
        return generator();
    else
        return {};
}

However, I usually like to use the ternary (?:) operator in these cases, so I tried using it this way (as usual):

return generator ? generator() : {};

But got this error:

somefile.cpp:143:46: error: expected primary-expression before ‘{’ token
somefile.cpp:143:46: error: expected ‘;’ before ‘{’ token

Does this mean I can't use the ternary operator to return objects created using their constructor from an initializer_list? Is there any particular reason for that?


回答1:


Standard writes in 8.5.4.1: List-initialization

Note: List-initialization can be used

  • as the initializer in a variable definition (8.5)
  • as the initializer in a new expression (5.3.4)
  • in a return statement (6.6.3)
  • as a function argument (5.2.2)
  • as a subscript (5.2.1)
  • as an argument to a constructor invocation (8.5, 5.2.3)
  • as an initializer for a non-static data member (9.2)
  • in a mem-initializer (12.6.2)
  • on the right-hand side of an assignment (5.17)

Nothing of them is a ternary operator. The more minimalistic return 1?{}:{}; is invalid too, what you want is impossible.

Of course you can explicitly call the constructor std::list<std::string>{}, but I would recommend to write out the if-else-block as you already did.




回答2:


When you do {} the compiler has no knowledge of the type you are expecting, so it's just a meaningless expression that the compiler doesn't know what to do with. Both sides of the : are evaluated separately, and only then will the compiler complain if the types don't match. I would just do this:

return generator ? generator() : std::list<std::string>();



回答3:


If you really like the ternary operator, you can try something like this:

return generator ? generator() : decltype(generator()) { "default value", "generator was empry" };

it will work even if you change the return types later.




回答4:


Another possibility is to define a wrapper function for the conditional operator:

template<class T> T& conditional(bool b, T&x, T&y) { return b ? x : y; }
template<class T> const T& conditional(bool b, const T&x, const T&y) { return b ? x : y; }

That allows you to call:

return conditional(generator, generator(), {});


来源:https://stackoverflow.com/questions/9982681/ternary-operator-c11-constructor-from-initializer-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!