(file), (std::istreambuf_iterator()));Который работает просто отлично, как е" />

Создать std :: string из std :: istreambuf_iterator, странная синтаксическая причуда

2645 просмотра

1 ответ

1988 Репутация автора

Я нашел где-то следующую идиому для чтения файла в строку:

std::ifstream file("path/to/some/file.ext");
std::string contents(
    std::istreambuf_iterator<char>(file),
    (std::istreambuf_iterator<char>())
);

Который работает просто отлично, как есть. Однако, если я уберу скобки вокруг второго аргумента итератора, то есть:

std::string contents(
    std::istreambuf_iterator<char>(file),
    std::istreambuf_iterator<char>()
);

Как только я пытаюсь вызвать любой метод для строкового объекта, например:

const char *buffer = contents.c_str();

Я получаю ошибку компиляции формы:

error: request for member 'c_str' in 'contents', which is of non-class type 'std::string(std::istreambuf_iterator<char, std::char_traits<char> >, std::istreambuf_iterator<char, std::char_traits<char> > (*)()) {aka std::basic_string<char>(std::istreambuf_iterator<char, std::char_traits<char> >, std::istreambuf_iterator<char, std::char_traits<char> > (*)())}'

Также, если я попытаюсь присвоить эту строку другой:

std::string contents2 = contents;

Я получаю ошибку в форме:

error: conversion from 'std::string(std::istreambuf_iterator<char, std::char_traits<char> >, std::istreambuf_iterator<char, std::char_traits<char> > (*)()) {aka std::basic_string<char>(std::istreambuf_iterator<char, std::char_traits<char> >, std::istreambuf_iterator<char, std::char_traits<char> > (*)())}' to non-scalar type 'std::string {aka std::basic_string<char>}' requested

Почему это? Я не вижу причин, по которым эти круглые скобки нужны, тем более они влияют на определение типа contentsпеременной. Я использую g ++ 4.8.2.

Автор: xperroni Источник Размещён: 27.08.2014 01:06

Ответы (1)


17 плюса

72555 Репутация автора

Решение

Вот пример Most Vexing Parse :

std::string contents(
    std::istreambuf_iterator<char>(file),
    std::istreambuf_iterator<char>()
);

Оператор анализируется как объявление именованной функции, contentsкоторая принимает два параметра. Один параметр - это переменная с именем fileтипа std::istreambuf_iterator, а второй - функция, которая не принимает аргументов и возвращает std::istreambuf_iterator. Указание имен параметров функции не является обязательным.

Обтекание хотя бы одного из выражений в скобках приводит к тому, что оно анализируется как определение переменной.

C ++ 11 решает эту проблему с помощью равномерной инициализации :

std::string contents{std::istreambuf_iterator<char>{file}, {}};
Автор: 0x499602D2 Размещён: 27.08.2014 01:13
Вопросы из категории :
32x32