Я работаю в среде с множеством заголовочных файлов, в некоторые из которых иногда проникает using namespace std;
. Я хочу уловить (в CI), когда это произойдет. Легко проверить, что что-то существует/компилируется, но наоборот на удивление сложно.
Моя идея заключалась в следующем:
#include "header1.h"
#include "header2.h"
// ...
static_assert(!type_is_defined(string))
Как я могу написать type_is_defined
так, чтобы он компилировался, когда string
не определен?
Я думаю, вы имеете в виду следующее: «Легко получить ошибку компилятора, когда что-то не объявлено», потому что для фактической «проверки» необходимо скомпилировать оба случая, и если вы это получите, то «противоположное» на самом деле будет просто отрицанием через !
Возможно, это невозможно, пока в C++ не будет добавлено отражение.
PS: Я удалил первоначальный комментарий, потому что думаю, что за это время понял, что вы хотите сказать.
мое замешательство связано с тем, что «легко проверить, что что-то существует/компилируется», а вы просите именно об этом;)
@463035818_is_not_an_ai, ну нет. Я не писал «Легко проверить, существует ли что-то/компилируется» (что было бы в обоих случаях). Другими словами, я написал: «Легко проверить, что что-то существует/компилируется» (просто написав это), но «Трудно проверить, что что-то не существует/не скомпилируется, при этом гарантируя, что код компилируется». Теперь это имеет больше смысла?
как я писал выше, имхо "проверка" подразумевает, что результат может быть отрицательным или положительным. Ничего, я понял.
using string = int;
в глобальном пространстве имен будет использовать string
без std::
сбоя с ошибкой компилятора, хотя это очень, очень серьезный взлом, который может иметь неприятные последствия. Не проще ли просто добавить еще одно задание CI, которое завершится сбоем, если grep -r "using namespace std;"
вернет какие-либо совпадения?
вам нужно как минимум объявить string
, тогда вы сможете проверить, определен ли он. Однако все попытки, которые я помню, имеют неопределенное поведение.
Я второй @Yksisarvinen. Это задача статического анализа, и ее можно решить, добавив еще один шаг CI, чтобы проверить, существует ли using namespace std;
в каждом файле. и ошибки, если он их найдет.
Возможно, это не самый элегантный способ, но он работает:
#include <string>
#include <type_traits>
//... many headers here, some of which may contain 'using namespace std;'
//using namespace std; //uncommenting it causes compiler error: "reference to 'string' is ambiguous"
class string;
static_assert(!std::same_as<string, std::string>);
Для static_assert
требуется C++20 из-за концепции same_as
. Для C++17 вам необходимо заменить его на is_same_v
. Если вы используете более раннюю версию C++, вы можете использовать следующее (что работает для C++11):
static_assert(!std::is_same<string, std::string>::value, "!");
Это хорошо, но, к сожалению, недоступно до C++20 и потерпит неудачу, если вы объявите using std::string
отдельно, даже не включая все пространство имен…
@Obsidian, для using std::string
это нормально, а я использую C++ 20.
@ 463035818_is_not_an_ai, нет, если вы удалите static_assert
, декларация не провалится, даже если вы раскомментируете using namespace std
@Юджин, извини, я виноват, я экспериментировал только с using std::string;
Вот одно решение:
#include <string>
// using std::string;
// using namespace std;
// Verify that string is not defined
// Fails with "redeclared as different kind of entity" if "using std::string"
void string() {}
void verify_string_undefined() {
// Fails with "ambiguous reference" if "using namespace std"
string();
}
int main() {}
Это не скомпилируется, как только строки 3 или 4 будут раскомментированы.
К сожалению, это запрещает использование using std::string
и string
после проверки.
Я работаю в среде с множеством заголовочных файлов, в некоторых из которых иногда используется пространство имен std; пробирается. Я хочу поймать (в CI), когда это произойдет.
Если это действительно ваш вопрос, а не конкретно о строке типа, то вы можете сделать это:
#include <charconv>
#include <type_traits>
// Define a non-existent overload of an std::function with a type that can be converted from the actual signature
// Make sure to use a different return type
static int to_chars( char*, char*, bool ){return 0;}
int main() {
// using namespace std; static assert will fail with this in place
static_assert(std::is_same_v<int,
// Make sure to use the type for the std:: signature here,
// not your custom function's converted type. So 1.0f and not true
decltype(to_chars(std::declval<char*>(),std::declval<char*>(),1.0f))
>, "using namespace std when we should not be");
}
@463035818_is_not_an_ai "Знаете ли вы, как реализовать type_is_defined(string)?" Нет, это именно мой вопрос. Ты? Ключ находится в положении «так, чтобы он компилировался, когда строка не определена». Какую бы реализацию
type_is_defined
я ни придумал, все они не скомпилируются, еслиstring
не определен, но это тот случай, когда мне нужно успешно скомпилировать.