Есть способ, но, к сожалению, это, вероятно, не тот способ, которым вы хотите.
Моей первой мыслью было попытаться заставить SFINAE сбрасывать со счетов перегрузку, расширяя недопустимую лямбду в невычисленном контексте. К сожалению (в вашем случае), это специально запрещено...
#define CODE { \
utter garbage \
}
struct test
{
template<class T>
static std::false_type try_compile(...) { return{}; }
template<class T>
static auto try_compile(int)
-> decltype([]() CODE, void(), std::true_type());
{ return {}; }
};
struct tag {};
using does_compile = decltype(test::try_compile<tag>(0));
выход:
./maybe_compile.cpp:88:17: error: lambda expression in an unevaluated operand
-> decltype([]() CODE, void(), std::true_type());
Итак, мы вернулись к чертежной доске и старому доброму системному вызову для обращения к компилятору...
#include <iostream>
#include <string>
#include <cstdlib>
#include <fstream>
#include <sstream>
struct temp_file {
temp_file()
: filename(std::tmpnam(nullptr))
{}
~temp_file() {
std::remove(filename.c_str());
}
std::string filename;
};
bool compiles(const std::string code, std::ostream& reasons)
{
using namespace std::string_literals;
temp_file capture_file;
temp_file cpp_file;
std::ofstream of(cpp_file.filename);
std::copy(std::begin(code), std::end(code), std::ostream_iterator<char>(of));
of.flush();
of.close();
const auto cmd_line = "c++ -x c++ -o /dev/null "s + cpp_file.filename + " 2> " + capture_file.filename;
auto val = system(cmd_line.c_str());
std::ifstream ifs(capture_file.filename);
reasons << ifs.rdbuf();
ifs.close();
return val == 0;
}
auto main() -> int
{
std::stringstream reasons1;
const auto code1 =
R"code(
#include <iostream>
int main() {
return 0;
}
)code";
std::cout << "compiles: " << compiles(code1, reasons1) << std::endl;
std::stringstream reasons2;
const auto code2 =
R"code(
#include <iostream>
int main() {
FOO!!!!XC@£$%^&*()VBNMYGHH
return 0;
}
)code";
std::cout << "compiles: " << compiles(code2, reasons2) << std::endl;
std::cout << "\nAnd here's why...\n";
std::cout << reasons2.str() << std::endl;
return 0;
}
который в моем случае дает следующий пример вывода:
compiles: 1
compiles: 0
And here's why...
/var/tmp/tmp.3.2dADZ7:4:9: error: use of undeclared identifier 'FOO'
FOO!!!!XC@£$%^&*()VBNMYGHH
^
/var/tmp/tmp.3.2dADZ7:4:19: error: non-ASCII characters are not allowed outside of literals and identifiers
FOO!!!!XC@£$%^&*()VBNMYGHH
^
2 errors generated.
конечно, вы можете добавить все необходимые макросы вокруг вызова compiles()
, чтобы его GTESTify. Вам, конечно, придется установить параметры командной строки при вызове c-компилятора, чтобы установить правильные пути и определения.
person
Richard Hodges
schedule
24.07.2015
#define static_assert assert
в верхней части тестового файла. Некрасиво, но, возможно, это то, что вы хотите. - person Lærne   schedule 15.10.2015