C++какой тип макроса __FILE__

Я пытаюсь создать класс исключений. Для этого я перегрузил оператор <<. Итак, код примерно такой

class RunAndCheck
{
     opearator << (boost::any given)
     {

         //Here goes the value of the    "given"

     }
};

Использование такое

RunAndCheck s;
s << file->open() << __FILE__ << __LINE__ ; 

Итак, проблема в том, что я хочу знать тип FILE, только тогда я могу извлечь строку из boost::any. Кто-нибудь может вызвать ваше любопытство по этому поводу?


person prabhakaran    schedule 21.02.2011    source источник


Ответы (3)


__FILE__ заменяется строковым литералом, как если бы вы напрямую написали «/path/to/current/file.cpp». Строковые литералы — это немодифицируемые lvalue массива символов.

Вы хотите использовать шаблон ‹‹ вместо использования boost::any:

class RunAndCheck {
public:
    template<class T>
    RunAndCheck& operator<<(const T& value) {
        // ...
        return *this;
    }
};

Или вы хотите предоставить перегрузки для всех допустимых типов:

class RunAndCheck {
public:
    RunAndCheck& operator<<(const char* value) {
        // ...
        return *this;
    }
    RunAndCheck& operator<<(int value) {
        // ...
        return *this;
    }
};
person Thomas Edleson    schedule 21.02.2011
comment
Я должен использовать некоторые условия if else, основанные на типе, например, если (ввод нет) cout ‹‹ строка нет ‹‹ нет, если (строка) cout ‹‹ имя файла ‹‹ имя_файла. Можете ли вы сказать, как этого добиться? - person prabhakaran; 21.02.2011
comment
@prabhakaran: обязательно посмотрите на ответ посетителя. Несмотря на то, что я решил проблему синтаксиса/типа, о которой вы спрашивали, другое решение является правильным семантическим решением. - person Thomas Edleson; 21.02.2011

Макросы не имеют типов, это просто замена текста, сделанная препроцессором (без проверки типов). Тип значения, вводимого __FILE__, является константной строкой C.

person jdehaan    schedule 21.02.2011
comment
@jdehaan Можете ли вы объяснить мне подробнее. C String означает CString или какой-либо другой - person prabhakaran; 21.02.2011
comment
@Stephane Rolland: const char* неверен, хотя вы можете получить это из строкового литерала. - person Thomas Edleson; 21.02.2011
comment
строка C не является классом. это константный литерал, точно если вы ввели "c:\path\file.cpp" непосредственно в исходный код. Тип этого строкового литерала — const char[]. - person tenfour; 21.02.2011
comment
@tenfour: технически его тип (эквивалентен) char[] по историческим причинам, хотя с ним всегда следует обращаться так, как если бы он был const. - person Fred Foo; 21.02.2011
comment
Говорить, что макросы не имеют типов, менее чем полезно. Значение, до которого раскрывается макрос, имеет тип, как и все значения. - person Jim Balter; 21.02.2011
comment
@ Джим, хорошее замечание, это косвенно то, что я имел в виду. @ Стефан, спасибо за точность, я тоже забыл это четко выразить. - person jdehaan; 21.02.2011
comment
На самом деле, я должен уточнить, что -- значение, до которого раскрывается макрос, имеет тип, если оно расширяется до значения... конечно, макросы могут расширяться до всех видов синтаксиса, кроме значений. __FILE__, однако, расширяется до значения. - person Jim Balter; 21.02.2011

__FILE__ заменяется строковым литералом, тип которого

const char[length_of_particular_string]

Вы действительно должны пересмотреть то, что вы делаете. (Мнение также основано на вашем предыдущем вопросе.)

Во-первых, boost::any для такого использования не годится (в частности, потому что тип строкового литерала в разных случаях будет разным). Но даже если бы не технические трудности, вам следует использовать обычную перегрузку функций.

Что еще более важно, кажется, что функциональность, которую вы хотите, состоит в том, чтобы получить логическое значение и выдать ошибку, содержащую имя файла и номер строки, если значение неверно. Поскольку вам всегда требуются все 3 компонента (хотя, согласно вашему описанию, было бы возможно, чтобы он выбрасывал, не указывая ему имя файла, или чтобы класс не делал ничего полезного), функция, которая принимает эти 3 аргумента, имеет больше смысла.

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

Полный пример:

#include <stdexcept>
#include <sstream>
#include <iostream>

void check_result(bool result, const char* line, int line_number)
{
    if (!result) {
        //for example:
        std::stringstream ss;
        ss << line << ' ' << line_number;
        throw std::runtime_error(ss.str()); 
    } 
} 

#define CALL_AND_CHECK(expression) check_result((expression), __FILE__, __LINE__)

bool foobar(bool b) { return b; }

int main()
{
    try {
        CALL_AND_CHECK(foobar(true));
        CALL_AND_CHECK(foobar(false));
    } catch (const std::exception& e) {
        std::cout << e.what() << '\n';
    }
}
person visitor    schedule 21.02.2011
comment
Очень хороший совет, но вы можете изменить __LINE__ на __FILE__. :) - person Thomas Edleson; 21.02.2011
comment
см. новое редактирование предыдущего вопроса ( stackoverflow.com/questions/5062699/… ; ). - person prabhakaran; 01.03.2011