Conditional expressions allow throw expressions as operands. I would like to have a conditional expression where one of the operands is an always-throw function, however it appears that this is not possible.
#include<exception>
[[ noreturn ]] void foo() {
throw std::exception();
}
int main() {
int a = true ? 1 : throw std::exception();
int b = true ? 1 : foo(); // This will not compile
}
I've tried inlining foo as well, but it wouldn't compile either. The error is the same:
test.cc: In function 'int main()':
test.cc:9:18: error: third operand to the conditional operator is of type 'void', but the second operand is neither a throw-expression nor of type 'void'
int b = true ? 1 : foo(); // This will not compile
Is there a way to achieve calling that function inside the expression? My use case is a transpiler from a language to C++ and that other language supports case expressions where if no case is hit in the expression, an exception is thrown. Case expressions I'm trying to support are similar to this:
http://zvon.org/other/haskell/Outputsyntax/caseQexpressions_reference.html
You can use the comma operator like so:
int a = true ? 1 : (throw std::exception(), 0);
int b = true ? 1 : (foo(), 0);
See it working on godbolt.org.
Related
If I have a constexpr function that can raise an exception at runtime, I want to make it able to give a compile error if it's evaluated at compile time.
#include <stdexcept>
#include <type_traits>
constexpr void func (const int x)
{
if (x == 0) {
if (std::is_constant_evaluated()) {
/// compile error
} else {
throw std::invalid_argument("x cannot be 0.");
}
}
}
I have tried putting static_assert inside the if statement, but it evaluates it regardless of the if statement (since the if is not constexpr I'm assuming). I have also tried static_assert(x != 0);, but it tells me non-constant condition for static assertion (which makes some sense...?).
Is there any (preferably easy) way to do this? Thanks.
EDIT: I generalized the function, in my case I have a constructor that I need to use to generate both compile time and run time objects. So I would like the program to give a compile error with a message like x cannot be 0 if I try to create a constexpr object with x being 0.
In the following code, I'd expect that both references to System.Action type to be represented as a QualifiedNameSyntax but the second one is represented as a MemberAccessExpressionSyntax.
Is that correct? If so, why can't it be a QualifiedNameSyntax?
class Foo
{
public void M(object o)
{
var t = typeof(System.Action); // 1
switch(o)
{
case System.Action: // 2
break;
}
}
}
Generally you're only going to get a QualifiedNameSyntax in a Roslyn syntax tree where the only legal thing there is a qualified name; in those cases we're running a restricted parser that will only understand qualified names. Anything else we're running our generic expression parser which will spit out whatever expression is there, and we'll figure out what it actually is during binding. Because consider another case like:
SomeEnum e;
switch (e)
{
case SomeEnum.Blue: Console.WriteLine("Blue!"); return;
}
In that case the SomeEnum.Blue is absolutely an access to a member. But we don't actually know what "SomeEnum" is until binding, so we just always go with MemberAccessExpression.
I can't tell you why for sure, but here's one relevant thing to think about:
In legal code, I think you're right that a switch can never accept a MemberAccessExpression, and so a QualifiedNameSyntax would be sufficient to represent this.
However let's look at some illegal code, and see what happens:
class Foo
{
public static void M(object o)
{
var t = typeof(Foo.M(5)); // 1
switch(o)
{
case Foo.M(5): // 2
break;
}
}
}
This gives 4 errors for the first usage of Foo.M(5):
error CS1026: ) expected
error CS1002: ; expected
error CS1513: } expected
error CS0426: The type name 'M' does not exist in the type 'Foo'
And only 1 for the second:
error CS0426: The type name 'M' does not exist in the type 'Foo'
By allowing a more flexible grammar in the second case, error messages are much better, as they can be done at the semantic level rather than a syntax level.
Since switch expressions accept any pattern as a case, it's more likely that you'll write something invalid, so good error messages are more important in that case.
I am trying make ternary operator work with lambda. Following is the logic that I want to cast into a ternary operation
if (boolean_condition_var == false) {
RandomMethod();
}
// From here some logic to execute
int i = 0;
// blah blah logic
Following is how I am trying to make it work after reading through this link.
boolean_condition_var == false ? RandomMethod() : std::function<void(void)>([this](){
// execute some logic here
int i = 0;
//blah blah logic
});
But I am getting the following error:
Issue:
error: left operand to ? is void, but right operand is of type 'std::function<void ()>'
boolean_condition_var == false ? RandomMethod() : std::function<void(void)>([this](){ int i = 0; });
Question:
How can I pass a lambda into the second clause of my ternary operator?
Since you are not calling the lambda, it makes little sense to create it. What you are trying to do is equivalent to
boolean_condition_var ? void(0) : RandomMethod();
On the other hand, if you want to call the lambda, use the call operator:
boolean_condition_var? ([this](){...your code...}) ( ) : RandomMethod();
// ^
// |
//--------------------------------------------------+
There's no need to cast anything to std::function.
A plain old if-then-else statement would be more welcome here.
On the third hand, if you want your ternary operator to return a callable, you probably need something like
using voidf = std::function<void(void)>;
auto result = boolean_condition_var?
voidf([this](){...your code...}):
voidf([this](){RandomNethod();});
.... result();
Capturing boolean_condition_var by value and moving the condition into the (now single) lambda could be more readable and more efficient though.
How can I pass a lambda into the second clause of my ternary operator?
Using comma operator ?
boolean_condition_var == false
? (RandomMethod(), 0)
: (std::function<void(void)>([this](){ /*...*/ })(), 0);
Or, I suppose better,
std::function<void(void)> logicElse { [this](){ /*...*/ } };
boolean_condition_var == false
? (RandomMethod(), 0)
: (logicElse(), 0);
I am assigning to a std::function<double()> a lambda expression. This snippet works
if(fn_type==exponential)
k.*variable = [=,&k](){ return initial*exp(-k.kstep*par); };
else
k.*variable = [=,&k](){ return initial*pow(k.kstep, par); };
whereas if I want to use the ternary operator
k.*variable = (fn_type==exponential ? [=,&k](){ return initial*exp(-k.kstep*par); } : [=,&k](){ return initial*pow(k.kstep, par); });
I get the following error:
error: no match for ternary ‘operator?:’ in <awfully long template error, because this whole thing is in a class defined in a function...>
Is this a gcc bug (I'm using 4.7.2)? Otherwise why is there this limit in the standard?
The second and third operands of the conditional operator must have the same type or there must be some common type to which they can both be converted that the compiler can figure out. There are only a handful of conversions that the compiler will consider.
Your two lambda expressions have different types, and there is no common type to which they can both be converted (conversions to user-defined types, like std::function<double()>, cannot be considered because there are potentially an infinite number of valid target types).
You can directly convert each of the operands to std::function<double()>:
k.*variable = fn_type==exponential
? std::function<double()>([=,&k](){ return initial*exp(-k.kstep*par); })
: std::function<double()>([=,&k](){ return initial*pow(k.kstep, par); });
But really, it's cleaner with the if/else.
Also faced this issue - won't compile!
'if/else' not good for me, I would like auto type deducing feature turn on.
auto memcpy_traits =
[&](uint8_t* line_dst, const uint8_t* curr_src, const size_t bytes_to_copy) {
std::memcpy(line_dst, curr_src, bytes_to_copy);
line_dst += bytes_to_copy;
curr_src += bytes_to_copy;
}
:
[&](uint8_t* line_dst, const uint8_t* curr_src, const size_t bytes_to_copy) {
std::memcpy(line_dst, curr_src, bytes_to_copy);
line_dst += bytes_to_copy;
curr_src += bytes_to_copy;
};
I'm trying to upgrade a Bada app from 1.2 to 2.0 with no experience of Bada. I have the project building and can run it in the emulator but I get a load of warnings and I cant click the text boxes to get a keyboard and enter anything in the emulator.
Unfortunately the warning messages are completely cryptic to me, for example
SearchForm::SearchForm(void) :
gives the warning message "when initialized here"
What when initialized here??!!
Also, all the TryCatch statements show syntax error, and nothing I have found on the internet seems to make it happy:
result OnDraw()
{
result r = E_SUCCESS;
Canvas* readerCanvas = GetCanvasN();
TryCatch(E_SUCCESS == GetLastResult(), "Failed to get canvas: %S", GetErrorMessage(r));
if (readerCanvas)
{
Rectangle tempRect(0, 0, GetBounds().width, GetBounds().height);
Point tempPoint(0, 0);
r = readerCanvas->Copy(tempPoint, *iDrawingCanvas, tempRect);
TryCatch(E_SUCCESS == r, "Failed to copy canvas: %S", GetErrorMessage(r));
delete readerCanvas;
}
return r;
CATCH:
delete readerCanvas;
return r;
}
The TryCatch line says "statement has no effect", if I try edit it to match the examples I'v found I get a syntax error.
What's up with this?
It seems like you are trying to outdo your IDE's supposed bad messages by quoting them entirely out of context and only partially. Let me break it down:
TryCatch
The macro is defined as
TryCatch(condition, cleanup, message)
When the condition is evaluated to false, this will goto CATCH. You could think of the macro like this:
if (!condition)
{
goto CATCH;
}
For example, you can use it like this:
void TryCatchDemo::UseTryCatch(void)
{
TryCatch(1==2, , "1 is NOT 2");
AppLog("This should not appear");
CATCH:
AppLog("Catch block");
}
Now, your second parameter is a string literal, "Failed to get canvas: %S", which unsurprisingly, doesn't have an effect when used as statement:
"does nothing";
123; // just like this
So the compiler is being nice to warn you of the fact that you probably had something else in mind. Note also, that statement has no effect is not a syntax error.
"when initialized here"
Know your language! The code quoted isn't legal C++ to begin with:
SearchForm::SearchForm(void) :
At best this is the beginning of a constructor definition, with a missing initializer list and body. In the C++ language spec, class members are initialized in the order in which they were declared, not in the order in which they appear in the initializer list. A minimal example:
struct X
{
int a, b;
X() : b(), a() {}
};
This results in the compiler warning:
/tmp/test.cpp|3 col 13| warning: ‘X::b’ will be initialized after [-Wreorder]
/tmp/test.cpp|3 col 10| warning: ‘int X::a’ [-Wreorder]
/tmp/test.cpp|4 col 6| warning: when initialized here [-Wreorder]
As you can see, you not only clipped the code but also the warnings! If you read the whole message and the whole code, the fix would be pretty obvious:
struct X
{
int a, b;
X() : a(), b() {}
};
Bonus: In case you were wondering, why the ordering matters, consider what happens when you do:
struct X
{
int a, b;
X() : b(), a(b) {} // OOPS!
};
Hope this helps
Using a Format String with the Macros
Edit I just noted this: it is probably not supported to use format strings inside the Try/Catch macros:
Each of the macros that support a message parameters actually support format strings. A format string is similar to the format string of printf on systems that support it (bada does NOT support it)