Ternary expression issue?

Hi. I'm playing around with some simple tutorials that i found online. just so i can get a better understanding of how stuff works. I'm kinda combining 2 tutorials into one just to hopefully absorb more faster. Something i've been interested in lately is ternary expressions. Everything else is working in this example except for the ternary expression. It works fine if i just have an either or expression but if i use it nested it doesn't work as expected. What exactly is the problem with it?

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
  
#include <iostream>
#include <string>
class Log
{
public:
    const int loglevelinfo = 0;const int loglevelwarning = 1;const int loglevelerror = 2;
private:
    int m_loglevel = 0;
public:
    void setlevel(int level)
    {
        m_loglevel = level;

    }

    void log(std::string message)
    {
        std::string sloglevel = m_loglevel > 1 ? m_loglevel < 2 && m_loglevel > 0 ? "error" : "warning" : "info";

        std::cout << sloglevel << " " << message << ' ' << m_loglevel << std::endl;

    }

};
int main()
{
    Log log;
    log.setlevel(log.loglevelerror);
   log.log("hello");
   
}

en interested in lately is ternary expressions. Everything else is working in this example except for the ternary expression. It works fine if i just have an either or expression but if i use it nested it doesn't work as expected.


Okay, so what exactly are you expecting?

Have you considered using parentheses?

If I'm parsing it correctly...
1
2
3
 (m_loglevel > 1) ?
            ((m_loglevel < 2 && m_loglevel > 0) ? "error" : "warning")
               : "info";

Let's follow the code:
You set loglevel to 2.
Then, outer ternary sees if loglevel > 1.
It is, so it goes into your nested ternary.
Then, inner ternary sees if loglevel < 2.
It isn't, so it sets it to warning.

So, your logic is just wrong.
(Furthermore, in my opinion, it's simply hard to parse as a human without indentation, even if it was correct).

I don't even suggest using ternary operator here. I'll edit my post in a few minutes with an alternative.
Edit:
1
2
3
4
5
    void log(std::string message)
    {
        static const char* log_level_LUT[] = { "info", "warning", "error" };
        std::cout << log_level_LUT[m_loglevel] << " " << message << " " << m_loglevel << '\n';
    }


PS:
(m_loglevel < 2 && m_loglevel > 0)

This is logically equivalent to m_loglevel == 1

PPS: Why add unnecessary state to your logger?
Why not just do "log.error()", "log.warning()" "log.info()"?
Or, log.log("message", Log::Error), log.log("message", Log::Warning), etc.
Last edited on
changed it to this and it works as expected. My lack of understanding was the issue. If both conditionals are true then sloglevel is set to error, if only the first one is true then sloglevel is set to warning, if none of them are true then info. but thanks.


1
2
3
4
5
6
7
8

 void log(std::string message)
    {
        std::string sloglevel = m_loglevel >=1 ? m_loglevel>=2 ? "error" : "warning" : "info";

        std::cout << sloglevel << " " << message << ' ' << m_loglevel << std::endl;

    }


FYI: If doesn't matter for most normal console output, but if you're redirecting your logging to a file, using std::endl will make your file writes considerably slower, because std::endl forces a flush.
Last edited on
If you format ?: like this
1
2
std::string sloglevel = log_level >= 2? "error"   : 
                        log_level >= 1? "warning" : "info";

It can be read as an if-else chain:
"if log_level >= 2 then 'error'; else if log_level >= 1 than 'warning'; else 'info'."
Last edited on
Topic archived. No new replies allowed.