Search code examples
c++parametersexpressionambiguityfunction-declaration

why is `std::istreambuf_iterator<char>` regard as function declaration when constrcuting a string?


Many coders may be confused this code:

int main() {
  std::ifstream ifs("filename", std::ios::binary);
  std::string content((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
  //                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
  ...
}

I would like to understand this code clearly, so the question is:

  1. Why is std::istreambuf_iterator<char>(ifs) enclosed in (, )?

  2. How to determinate this code if remove the brackets here? and

  3. How to determinate the code if we don't remove the brackets?

Thanks for your help.


Solution

  • In declarations declarators may be enclosed in parentheses.

    Consider the following function declaration

    void f( int ( x ), int ( y ) );
    

    This declaration declares a function with two parameters of the type int.

    In a declaration names of identifiers may be omitted.

    So you may write

    void f( int (), int () );
    

    This declaration in turn declares a function that accepts two parameters of the function type int().

    So this construction

    std::string content(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());
    

    can be considered by the compiler as a declaration of a function that has the return type std::string and with the first parameter of the type std::istreambuf_iterator<char> and the identifier ifs and the second parameter with the function type istreambuf_iterator<char>().

    To distinguish a declaration from an expression there are used either parentheses like

    std::string content( ( std::istreambuf_iterator<char>(ifs) ), std::istreambuf_iterator<char>());
    

    or braces

    std::string content(std::istreambuf_iterator<char>{ ifs }, std::istreambuf_iterator<char>());
    

    Here is a demonstration program that shows how can look declarators in parameter declarations.

    #include <iostream>
    
    void f( int ( x ), int ( y ) )
    {
        std::cout << "x = " << x << ", y = " << y << '\n';
    }
    
    void f( int(), int() );
    
    void f( int g(), int h() )
    {
        std::cout << g() + h() << '\n';
    }    
    
    int g() { return 100; }
    
    int main()
    {
        f( 10, 20 );    
    
        f( g, g );
    }
    

    The program output is

    x = 10, y = 20
    200
    

    As for the question appeared in a comment about declaration of a parameter of a function type then for example the C function qsort uses such a parameter that specifiers the relation between two elements of an array.

    void qsort(void *base, size_t nmemb, size_t size,
    int compar(const void *, const void *));
    

    Another example is of using a function type as a template argument for a class template std::function.