Theo như tôi biết, đó là không thể (không portably). Tuy nhiên, từ chữ ký đầy đủ, bạn có thể trích xuất các đối số đó. Tất nhiên nó đòi hỏi phải phân tích cho biết chữ ký ... mà không phải là dễ dàng như vậy: x
Dưới đây là chức năng tôi sử dụng tại thời điểm này:
// What we want to consume:
// void
// signed short
// unsigned int
// Test::Bar<T, N>
//
static char const* consumeType(char const* const begin, char const* const end){
static StringRef const Signed("signed");
static StringRef const Unsigned("unsigned");
char const* it = begin;
if (startsWith(it, Signed)) { it += Signed.size() + 1; }
else if (startsWith(it, Unsigned)) { it += Unsigned.size() + 1; }
// jump over the return type
size_t templateNest = 0;
while (it != end) {
if (*it == ' ' and templateNest == 0) { break; }
if (*it == '<') { ++templateNest; }
if (*it == '>' and templateNest > 0) { --templateNest; }
++it;
}
return it;
} // consumeType
//
// \param signature: signature as returned by __func___ on gcc
// \return: full name, included namespace qualifier and class (if any)
//
// void Test::Bar<T, N>::parameterized(U) const
// [with unsigned int O = 4u, U = Test::Foo,
// T = Test::Foo, unsigned int N = 3u]
// -> Test::Bar<T, N>::parameterized
//
StringRef parseFunctionName(StringRef const signature) {
char const* begin = signature.begin();
char const* end = signature.end();
// Jump over the return type
begin = consumeType(begin, end);
if (begin == end) { return signature; }
// skip the space right after the return type
++begin;
if (begin == end) { return signature; }
// if we encounter a '(' then it means that we return a function,
// and we once again need to jump over the return type
if (*begin == '(') {
begin = consumeType(++begin, end);
// skip the space
++begin;
if (begin == end) { return signature; }
}
// and finally, we got the beginning, and we need to get the end, which is
// the first opening '('
char const* e = std::find(begin, end, '(');
return StringRef(begin, e - begin);
} // parseFunctionName
Và accompagnying nó kiểm tra:
#define UT_FUNCTION_CHECK(Signature_, Name_) \
UT_CHECK(parseFunctionName(StringRef(Signature_)) == Name_);
void Function() {
// Regular functions
UT_FUNCTION_CHECK("int main()", "main")
UT_FUNCTION_CHECK("int foo(int, double)", "foo")
UT_FUNCTION_CHECK("unsigned int foo(int, double)", "foo")
// Templates
UT_FUNCTION_CHECK("unsigned int Test::Bar<T, N>::print() const"
" [with T = Test::Foo, unsigned int N = 3u]",
"Test::Bar<T, N>::print")
UT_FUNCTION_CHECK("Test::Bar<T, N> Test::Bar<T, N>::print() const"
" [with T = Test::Foo, unsigned int N = 3u]",
"Test::Bar<T, N>::print")
UT_FUNCTION_CHECK("void Test::Bar<T, N>::parameterized(U) const"
" [with unsigned int O = 4u, U = Test::Foo,"
" T = Test::Foo, unsigned int N = 3u]",
"Test::Bar<T, N>::parameterized")
// Functions returning functions
UT_FUNCTION_CHECK("void (* Test::Foo::func() const)()",
"Test::Foo::func")
UT_FUNCTION_CHECK("void (Test::Foo::* Test::Foo::method() const)(int)volatile",
"Test::Foo::method")
UT_FUNCTION_CHECK("void (Test::Foo::* Test::Foo::super())"
"(void (Test::Foo::*)(int)volatile)const",
"Test::Foo::super")
} // Function
Nó hoạt động kết hợp với macro __func__
của gcc.
Lớp StringRef
tương tự như llvm::StringRef
.
Tôi nghĩ rằng nó nên đáp ứng nhu cầu của bạn nếu bạn có thể đủ khả năng phân tích thêm. Nó khá nhanh: không có backtracking và không có phân bổ động, vì vậy không phải là một vấn đề (đặc biệt là so với viết vào một tập tin ...).
Hy vọng điều đó sẽ hữu ích.
Tôi không nghĩ rằng có bất kỳ nền tảng độc lập nào để có được chữ ký đầy đủ của hàm. Tuy nhiên, tại sao bạn không thể sử dụng combo của '__FILE__' và' __LINE__'? Nó sẽ cho bạn gần như cùng một hiệu ứng; hơn nữa là nhanh hơn để xác định vị trí trong mã của bạn từ các bản ghi so với tìm kiếm một hàm! – iammilind
@iammilind: Thực ra, tôi muốn sử dụng nội dung macro làm tên logger trong log4cxx. Những tên logger này có thứ bậc và bạn có thể thiết lập các mức log khác nhau cho các không gian tên khác nhau, vv Vì vậy, những gì tôi thực sự làm là một cái gì đó giống như logger Logger Logger Logtr Logger Logger Logger Logger Logger Logger Logger Log Log ; LOG4CXX_INFO (logger, "blah logging blah"); 'MACRO sẽ điền vào phần' foo.bar.baz'. Tôi không muốn làm cho nó phức tạp trong bài viết của mình. – Frank