Home > Blockchain >  Is there a constexpr which lets me determine if there is an output operator (<<) for a particu
Is there a constexpr which lets me determine if there is an output operator (<<) for a particu

Time:03-04

In order to prevent the compiler to apply e.g. a std::vector<T> to a statement like std::cout << u, I would like to do something like this:

if constexpr (std::has_output_operator<U>) {
    std::cout << u;
}

Is there some way to achieve this?

EDIT (clarification) I am working on printf-like function which can also print strings and vectors of POD and strings (and vectors thereof).

I would like to extend this functionality to any type which has an output operator.

The actual formatting for non-vector types is done by the functions simpleFormat():

// simpleFormat
//  special case for single string
//
std::string simpleFormat(const std::string sFormat, const std::string t) {
    size_t required = snprintf(NULL, 0, sFormat.c_str(), t.c_str());
    char sTemp[required 1];
    sprintf(sTemp, sFormat.c_str(), t.c_str());
    return std::string(sTemp);
} 

// simpleFormat
//  catch for vectors (should not be sent to simpleFormat)
template<typename T>
std::string simpleFormat(const std::string sFormat, const std::vector<T> t) {
    return "";
}

// simpleFormat
//  formatting PODs and Objects with output operator a char using     
template<typename T>
std::string simpleFormat(const std::string sFormat, const T t) {
    std::string sRes = "";

    if (sFormat.size() > 0) {
        if (sFormat != "%O") {
            size_t required = snprintf(NULL, 0, sFormat.c_str(), t);
            char sTemp[required 1];
            sprintf(sTemp, sFormat.c_str(), t);
            sRes = std::string(sTemp);
        } else {
            std::stringstream ss("");
            ss << t;
            sRes  = ss.str();    
        }
    } 

   return sRes;
}

When i compile this for some applications, get the error

In file included from AgentCounter.cpp:6: 
../utils/stdstrutilsT.h: In instantiation of ‘std::string simpleFormat(std::string, T) [with T = __gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > >; std::string = std::__cxx11::basic_string<char>]’: 
../utils/stdstrutilsT.h:195:33:   required from ‘std::string recursiveFormat(stringvec&, stringvec&, uint, T, Args ...) [with T = __gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > >; Args = {long long unsigned int}; std::string = std::__cxx11::basic_string<char>; stringvec = std::vector<std::__cxx11::basic_string<char> >; uint = unsigned int]’ 
../utils/stdstrutilsT.h:281:31:   required from ‘std::string stdsprintf(std::string, Args ...) [with Args = {__gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, long long unsigned int}; std::string = std::__cxx11::basic_string<char>]’ 
../utils/stdstrutilsT.h:291:34:   required from ‘void stdprintf(std::string, Args ...) [with Args = {__gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, long long unsigned int}; std::string = std::__cxx11::basic_string<char>]’ 
AgentCounter.cpp:326:22:   required from here 
../utils/stdstrutilsT.h:165:28: error: no match for ‘operator<<’ (operand types are ‘std::stringstream’ {aka ‘std::__cxx11::basic_stringstream<char>’} and ‘const __gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > >’) 
 165 |                         ss << t; 
     |                         ~~~^~~~ 

Even though i have a simpleFormat() variant for vectors, the compiler still wants to fit the std::vector into the POD variant.

That is why i hope there is constexpr which lets me find out if the passed type has an output operator.

Of course if there are other possibilities to stop the compiler from applying vectors to my non-vector function, i'd like to learn about them.

CodePudding user response:

This can be done straightforwardly using the C 20 requires-expression, which checks whether its operand is valid:

if constexpr (requires { std::cout << u; })

You can also define a named concept with the requires-expression and then use it in place of the requires-expression every time you need it.

  • Related