Say I have a dummy class like this:
class Stack
{
public:
template<typename T>
void push(T val)
{ (void)val; }
template<typename T>
T pop()
{ return 0; }
bool empty() const
{ return true; }
};
The AST dump of which looks like:
...
|-CXXRecordDecl 0x5610df147d60 <col:1, col:7> col:7 implicit class Stack
|-AccessSpecDecl 0x5610df147df0 <line:3:1, col:7> col:1 public
|-FunctionTemplateDecl 0x5610df1480e0 <line:4:3, line:6:16> line:5:8 push
| |-TemplateTypeParmDecl 0x5610df147e18 <line:4:12, col:21> col:21 referenced typename depth 0 index 0 T
| `-CXXMethodDecl 0x5610df148040 <line:5:3, line:6:16> line:5:8 push 'void (T)'
| |-ParmVarDecl 0x5610df147f00 <col:13, col:15> col:15 referenced val 'T'
| `-CompoundStmt 0x5610df1484f0 <line:6:3, col:16>
| `-CStyleCastExpr 0x5610df1484c8 <col:5, col:11> 'void' <ToVoid>
| `-DeclRefExpr 0x5610df148498 <col:11> 'T' lvalue ParmVar 0x5610df147f00 'val' 'T'
|-FunctionTemplateDecl 0x5610df148300 <line:8:3, line:10:15> line:9:5 pop
| |-TemplateTypeParmDecl 0x5610df148140 <line:8:12, col:21> col:21 referenced typename depth 0 index 0 T
| `-CXXMethodDecl 0x5610df148260 <line:9:3, line:10:15> line:9:5 pop 'T ()'
| `-CompoundStmt 0x5610df148538 <line:10:3, col:15>
| `-ReturnStmt 0x5610df148528 <col:5, col:12>
| `-IntegerLiteral 0x5610df148508 <col:12> 'int' 0
`-CXXMethodDecl 0x5610df1483e0 <line:12:3, line:13:18> line:12:8 empty 'bool () const'
`-CompoundStmt 0x5610df148570 <line:13:3, col:18>
`-ReturnStmt 0x5610df148560 <col:5, col:12>
`-CXXBoolLiteralExpr 0x5610df148550 <col:12> 'bool' true
Given access to the CXXRecordDecl node for Stack, how can I access the FunctionTemplateDecl objects for push and pop? CXXRecorDecl::methods only returns the method declaration for empty and I don't see any other functions that might be helpful. Do I have to match the function template declarations separately and then later associate them with the class declaration?
I believe I have now figured it out, I will answer my own question in case this is useful for someone else:
The way to do this is to first cast the given CXXRecordDecl to DeclContext, iterate over the contained declarations and try to cast them to FunctionTemplateDecl, pseudocode:
clang::CXXRecordDecl const *record = // ...
for (auto const *inner : static_cast<clang::DeclContext>(record)->decls()) {
auto const *member_function_template = llvm::dyn_cast<clang::FunctionTemplateDecl>(inner);
if (!member_function_template)
continue;
// do something useful
}
Related
#include <iostream>
#include <string>
typedef std::string S;
template <typename T>
static inline T* getOrCreate( ( []() -> auto) creationSpren *) {
bool assigned = false;
if (!assigned) {
// invoke creationSpren with passed arguments
// assign
}
}
int main()
{
auto& xx = []() {
return new std::string("abc");
};
auto& zzz = getOrCreate<S>(xx);
}
note: this code does not compile, that is the problem I am trying to solve.
however, I wrote this minimum example to illustrate the problem, it is as barebones as possible.
What I'm trying to achieve is simple, to use lambdas to achieve lazy initialization of an object, when it is needed (i.e. when a retrieve fails, it calls the lambda and assigns the object (i.e. stores it) and returns it)
What I have problems with, as I have no experience with lambdas is both the signatures.
That is what I am asking, how to write the 2 lambda signatures. thanks.
and yes, it needs to be templated.
verbatim errors
<source>: In lambda function:
<source>:7:45: error: expected '{' before ')' token
7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) {
| ^
<source>: At global scope:
<source>:7:46: error: expected ')' before 'creationSpren'
7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) {
| ~ ^~~~~~~~~~~~~~
| )
<source>:7:63: error: expected ';' before '{' token
7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) {
| ^~
| ;
<source>: In function 'int main()':
<source>:18:16: error: cannot bind non-const lvalue reference of type 'main()::<lambda()>&' to an rvalue of type 'main()::<lambda()>'
18 | auto& xx = []() {
| ^~~~~~
19 | return new std::string("abc");
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 | };
| ~
<source>: In instantiation of 'std::__cxx11::basic_string<char>* getOrCreate<std::__cxx11::basic_string<char> >':
<source>:22:17: required from here
<source>:7:33: error: cannot convert '<lambda()>' to 'std::__cxx11::basic_string<char>*' in initialization
7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) {
| ^~~~~~~~~~~~
| |
| <lambda()>
<source>:22:31: error: 'getOrCreate<std::__cxx11::basic_string<char> >' cannot be used as a function
22 | auto& zzz = getOrCreate<S>(xx);
| ~~~~~~~~~~~~~~^~~~
ASM generation compiler returned: 1
<source>: In lambda function:
<source>:7:45: error: expected '{' before ')' token
7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) {
| ^
<source>: At global scope:
<source>:7:46: error: expected ')' before 'creationSpren'
7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) {
| ~ ^~~~~~~~~~~~~~
| )
<source>:7:63: error: expected ';' before '{' token
7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) {
| ^~
| ;
<source>: In function 'int main()':
<source>:18:16: error: cannot bind non-const lvalue reference of type 'main()::<lambda()>&' to an rvalue of type 'main()::<lambda()>'
18 | auto& xx = []() {
| ^~~~~~
19 | return new std::string("abc");
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 | };
| ~
<source>: In instantiation of 'std::__cxx11::basic_string<char>* getOrCreate<std::__cxx11::basic_string<char> >':
<source>:22:17: required from here
<source>:7:33: error: cannot convert '<lambda()>' to 'std::__cxx11::basic_string<char>*' in initialization
7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) {
| ^~~~~~~~~~~~
| |
| <lambda()>
<source>:22:31: error: 'getOrCreate<std::__cxx11::basic_string<char> >' cannot be used as a function
22 | auto& zzz = getOrCreate<S>(xx);
| ~~~~~~~~~~~~~~^~~~
Execution build compiler returned: 1
If you look at the standard library and their functions which takes a callable object, it uses templates.
I recommend that for your function as well:
template<typename T, typename F>
static inline T* getOrCreate(F creationSpren)
{
// ...
}
There's another problem with your current function: The variable assigned is a normal local variable. It will be created and initialized to false each time getOrCreate is called.
You need to make it a static local variable.
If you need to pass argument to getOrCreate that are then forwarded to the creationSpren function, then use template parameter packs:
#include <utility>
#include <iostream>
template<typename T, typename F, typename ...A>
static inline T* getOrCreate(F creationSpren, A&& ...args)
{
creationSpren(std::forward<A>(args)...);
return nullptr;
}
int main()
{
auto lambda_noargs = []() { std::cout << "No arguments\n"; };
auto lambda_twoargs = [](int, int) { std::cout << "Two arguments\n"; };
getOrCreate<int>(lambda_noargs);
getOrCreate<int>(lambda_twoargs, 1, 2);
}
what you have now is just a complicated version of static local variable. (usually used in singleton)
int main(){
auto xx = []{
static std::string* v = new std::string("abc");
return v;
};
std::string* a = xx();
std::string* b = xx();
assert(a==b);
delete a; // manually cleanup as you `new` it
}
https://godbolt.org/z/GnsGaqnx3
i kown it's about gtest framework, i can use gtest for my own demo but in leveldb repo i don't know how to build a single test file such as:leveldb/db/db_test.cc, it will report other confused errors.
precondition:
what i want is debug a single testfile such as db_test.cc.
i use vscode, this is part of my task.json which i think already contains all needed:
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}",
"-I", "/root/wzy/code/cpp/leveldb/include",
"-I", "/root/wzy/code/cpp/leveldb",
"-I", "/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include",
"-L", "/root/wzy/code/cpp/leveldb/build",
"-lleveldb",
"-lsnappy",
"-pthread"
]
and build errors like these:
/usr/bin/g++ -fdiagnostics-color=always -g /root/wzy/code/cpp/leveldb/db/db_test.cc -o /root/wzy/code/cpp/leveldb/db/db_test -I /root/wzy/code/cpp/leveldb/include -I /root/wzy/code/cpp/leveldb -I /root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include -L /root/wzy/code/cpp/leveldb/build -lleveldb -lsnappy -lpthread
In file included from /root/wzy/code/cpp/leveldb/db/db_test.cc:12:
/root/wzy/code/cpp/leveldb/db/db_impl.h:174:3: error: 'port' does not name a type
174 | port::Mutex mutex_;
| ^~~~
/root/wzy/code/cpp/leveldb/db/db_impl.h:176:3: error: 'port' does not name a type
176 | port::CondVar background_work_finished_signal_ GUARDED_BY(mutex_);
| ^~~~
In file included from /root/wzy/code/cpp/leveldb/db/db_test.cc:14:
/root/wzy/code/cpp/leveldb/db/version_set.h:181:41: error: 'port' has not been declared
181 | Status LogAndApply(VersionEdit* edit, port::Mutex* mu)
| ^~~~
/root/wzy/code/cpp/leveldb/db/version_set.h:181:52: error: expected ',' or '...' before '*' token
181 | Status LogAndApply(VersionEdit* edit, port::Mutex* mu)
| ^
In file included from /root/wzy/code/cpp/leveldb/db/db_test.cc:24:
/root/wzy/code/cpp/leveldb/util/mutexlock.h:25:22: error: 'port' has not been declared
25 | explicit MutexLock(port::Mutex* mu) EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
| ^~~~
/root/wzy/code/cpp/leveldb/util/mutexlock.h:25:33: error: expected ')' before '*' token
25 | explicit MutexLock(port::Mutex* mu) EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
| ~ ^
| )
/root/wzy/code/cpp/leveldb/util/mutexlock.h:34:3: error: 'port' does not name a type
34 | port::Mutex* const mu_;
| ^~~~
/root/wzy/code/cpp/leveldb/util/mutexlock.h: In destructor 'leveldb::MutexLock::~MutexLock()':
/root/wzy/code/cpp/leveldb/util/mutexlock.h:28:42: error: 'class leveldb::MutexLock' has no member named 'mu_'
28 | ~MutexLock() UNLOCK_FUNCTION() { this->mu_->Unlock(); }
| ^~~
In file included from /root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-spec-builders.h:75,
from /root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-function-mocker.h:42,
from /root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock.h:61,
from /root/wzy/code/cpp/leveldb/util/testutil.h:8,
from /root/wzy/code/cpp/leveldb/db/db_test.cc:25:
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h: In member function 'testing::internal::FieldsAreMatcher<Inner>::operator testing::Matcher<T>() const':
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:3165:49: error: 'IndexSequenceFor' was not declared in this scope; did you mean 'IndexSequence'?
3165 | new FieldsAreMatcherImpl<const Struct&, IndexSequenceFor<Inner...>>(
| ^~~~~~~~~~~~~~~~
| IndexSequence
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:3165:71: error: expected parameter pack before '...'
3165 | new FieldsAreMatcherImpl<const Struct&, IndexSequenceFor<Inner...>>(
| ^~~
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:3165:71: error: template argument 2 is invalid
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h: At global scope:
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4291:21: error: 'StringLike' in namespace 'testing::internal' does not name a template type; did you mean 'Strings'?
4291 | const internal::StringLike<T>& str) {
| ^~~~~~~~~~
| Strings
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4291:31: error: expected ',' or '...' before '<' token
4291 | const internal::StringLike<T>& str) {
| ^
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h: In function 'testing::PolymorphicMatcher<testing::internal::StrEqualityMatcher<std::__cxx11::basic_string<char> > > testing::StrEq(int)':
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4293:61: error: 'str' was not declared in this scope; did you mean 'std'?
4293 | internal::StrEqualityMatcher<std::string>(std::string(str), true, true));
| ^~~
| std
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h: At global scope:
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4299:21: error: 'StringLike' in namespace 'testing::internal' does not name a template type; did you mean 'Strings'?
4299 | const internal::StringLike<T>& str) {
| ^~~~~~~~~~
| Strings
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4299:31: error: expected ',' or '...' before '<' token
4299 | const internal::StringLike<T>& str) {
| ^
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h: In function 'testing::PolymorphicMatcher<testing::internal::StrEqualityMatcher<std::__cxx11::basic_string<char> > > testing::StrNe(int)':
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4301:61: error: 'str' was not declared in this scope; did you mean 'std'?
4301 | internal::StrEqualityMatcher<std::string>(std::string(str), false, true));
| ^~~
| std
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h: At global scope:
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4307:21: error: 'StringLike' in namespace 'testing::internal' does not name a template type; did you mean 'Strings'?
4307 | const internal::StringLike<T>& str) {
| ^~~~~~~~~~
| Strings
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4307:31: error: expected ',' or '...' before '<' token
4307 | const internal::StringLike<T>& str) {
| ^
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h: In function 'testing::PolymorphicMatcher<testing::internal::StrEqualityMatcher<std::__cxx11::basic_string<char> > > testing::StrCaseEq(int)':
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4309:61: error: 'str' was not declared in this scope; did you mean 'std'?
4309 | internal::StrEqualityMatcher<std::string>(std::string(str), true, false));
| ^~~
| std
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h: At global scope:
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4315:21: error: 'StringLike' in namespace 'testing::internal' does not name a template type; did you mean 'Strings'?
4315 | const internal::StringLike<T>& str) {
| ^~~~~~~~~~
| Strings
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4315:31: error: expected ',' or '...' before '<' token
4315 | const internal::StringLike<T>& str) {
| ^
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h: In function 'testing::PolymorphicMatcher<testing::internal::StrEqualityMatcher<std::__cxx11::basic_string<char> > > testing::StrCaseNe(int)':
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4317:19: error: 'str' was not declared in this scope; did you mean 'std'?
4317 | std::string(str), false, false));
| ^~~
| std
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h: At global scope:
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4324:21: error: 'StringLike' in namespace 'testing::internal' does not name a template type; did you mean 'Strings'?
4324 | const internal::StringLike<T>& substring) {
| ^~~~~~~~~~
| Strings
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4324:31: error: expected ',' or '...' before '<' token
4324 | const internal::StringLike<T>& substring) {
| ^
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h: In function 'testing::PolymorphicMatcher<testing::internal::HasSubstrMatcher<std::__cxx11::basic_string<char> > > testing::HasSubstr(int)':
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4326:59: error: 'substring' was not declared in this scope; did you mean 'IsSubstring'?
4326 | internal::HasSubstrMatcher<std::string>(std::string(substring)));
| ^~~~~~~~~
| IsSubstring
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h: At global scope:
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4332:21: error: 'StringLike' in namespace 'testing::internal' does not name a template type; did you mean 'Strings'?
4332 | const internal::StringLike<T>& prefix) {
| ^~~~~~~~~~
| Strings
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4332:31: error: expected ',' or '...' before '<' token
4332 | const internal::StringLike<T>& prefix) {
| ^
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h: In function 'testing::PolymorphicMatcher<testing::internal::StartsWithMatcher<std::__cxx11::basic_string<char> > > testing::StartsWith(int)':
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4334:60: error: 'prefix' was not declared in this scope; did you mean 'profil'?
4334 | internal::StartsWithMatcher<std::string>(std::string(prefix)));
| ^~~~~~
| profil
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h: At global scope:
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4340:21: error: 'StringLike' in namespace 'testing::internal' does not name a template type; did you mean 'Strings'?
4340 | const internal::StringLike<T>& suffix) {
| ^~~~~~~~~~
| Strings
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4340:31: error: expected ',' or '...' before '<' token
4340 | const internal::StringLike<T>& suffix) {
| ^
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h: In function 'testing::PolymorphicMatcher<testing::internal::EndsWithMatcher<std::__cxx11::basic_string<char> > > testing::EndsWith(int)':
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:4342:58: error: 'suffix' was not declared in this scope
4342 | internal::EndsWithMatcher<std::string>(std::string(suffix)));
| ^~~~~~
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h: In member function 'bool testing::internal::ExceptionMatcherImpl<Err>::MatchAndExplain(T&&, testing::MatchResultListener*) const':
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:5150:77: error: no matching function for call to 'GetTypeName(const std::type_info&)'
5150 | *listener << "throws an exception of type " << GetTypeName(typeid(err));
| ^
In file included from /usr/include/gtest/internal/gtest-internal.h:67,
from /usr/include/gtest/gtest.h:62,
from /root/wzy/code/cpp/leveldb/db/db_test.cc:11:
/usr/include/gtest/internal/gtest-type-util.h:80:13: note: candidate: 'template<class T> std::string testing::internal::GetTypeName()'
80 | std::string GetTypeName() {
| ^~~~~~~~~~~
/usr/include/gtest/internal/gtest-type-util.h:80:13: note: template argument deduction/substitution failed:
In file included from /root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-spec-builders.h:75,
from /root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-function-mocker.h:42,
from /root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock.h:61,
from /root/wzy/code/cpp/leveldb/util/testutil.h:8,
from /root/wzy/code/cpp/leveldb/db/db_test.cc:25:
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-matchers.h:5150:77: note: candidate expects 0 arguments, 1 provided
5150 | *listener << "throws an exception of type " << GetTypeName(typeid(err));
| ^
In file included from /root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock.h:63,
from /root/wzy/code/cpp/leveldb/util/testutil.h:8,
from /root/wzy/code/cpp/leveldb/db/db_test.cc:25:
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-more-actions.h: In member function 'decltype (testing::internal::InvokeArgument(get<index>(std::forward_as_tuple((forward<Args>)(args)...)), (declval<const Params&>)()...)) testing::internal::InvokeArgumentAction<index, Params>::operator()(Args&& ...) const':
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-more-actions.h:519:47: error: 'FlatTupleConstructTag' was not declared in this scope
519 | internal::FlatTuple<Args&&...> args_tuple(FlatTupleConstructTag{},
| ^~~~~~~~~~~~~~~~~~~~~
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-more-actions.h: In function 'testing::internal::InvokeArgumentAction<index, typename std::decay<Params>::type ...> testing::InvokeArgument(Params&& ...)':
/root/wzy/code/cpp/leveldb/third_party/googletest/googlemock/include/gmock/gmock-more-actions.h:564:17: error: 'FlatTupleConstructTag' is not a member of 'testing::internal'
564 | internal::FlatTupleConstructTag{}, std::forward<Params>(params)...)};
| ^~~~~~~~~~~~~~~~~~~~~
/root/wzy/code/cpp/leveldb/db/db_test.cc: At global scope:
/root/wzy/code/cpp/leveldb/db/db_test.cc:61:3: error: 'port' does not name a type
61 | port::Mutex mu_;
| ^~~~
/root/wzy/code/cpp/leveldb/db/db_test.cc: In member function 'void leveldb::{anonymous}::AtomicCounter::IncrementBy(int)':
/root/wzy/code/cpp/leveldb/db/db_test.cc:48:18: error: 'mu_' was not declared in this scope
48 | MutexLock l(&mu_);
| ^~~
/root/wzy/code/cpp/leveldb/db/db_test.cc: In member function 'int leveldb::{anonymous}::AtomicCounter::Read()':
/root/wzy/code/cpp/leveldb/db/db_test.cc:52:18: error: 'mu_' was not declared in this scope
52 | MutexLock l(&mu_);
| ^~~
/root/wzy/code/cpp/leveldb/db/db_test.cc: In member function 'void leveldb::{anonymous}::AtomicCounter::Reset()':
/root/wzy/code/cpp/leveldb/db/db_test.cc:56:18: error: 'mu_' was not declared in this scope
56 | MutexLock l(&mu_);
thanks #Tsyvarev, I defined a LEVELDB_PLATFORM_POSIX in source and this "prot" err is missing, but other errs still exist, I will keep doing this till I can GDB a single gtest file.
I have a class and I wanna specialize a function in that class.
I need something like this:
class A
{
public:
template <typename T>
T fun()
{
throw new Exception("Unsupported template param");
}
template <>
bool fun<bool>()
{
return true;
}
template <>
float fun<float>()
{
return 5.6f;
}
template <>
double fun<double>()
{
return 5.684;
}
};
It works if I use the function without a class but if I put the function to the class I will get a lot of errors.
Example:
template <>
bool fun<bool>()
{
return true;
}
template <>
float fun<float>()
{
return 5.6f;
}
template <>
double fun<double>()
{
return 5.684;
}
It works. But when I declare fun in some class it doesn't work.
Errors: (Sorry for Russian language but my OS is translated to russian)
/home/aleksey/Документы/Проекты/tests/color-c/source/app.cpp:12:15: ошибка: явная специализация в не-namespace области «class A»
12 | template <>
| ^
/home/aleksey/Документы/Проекты/tests/color-c/source/app.cpp:13:10: ошибка: template-id «fun<bool>» in declaration of primary template
13 | bool fun<bool>()
| ^~~~~~~~~
/home/aleksey/Документы/Проекты/tests/color-c/source/app.cpp:18:15: ошибка: явная специализация в не-namespace области «class A»
18 | template <>
| ^
/home/aleksey/Документы/Проекты/tests/color-c/source/app.cpp:19:11: ошибка: template-id «fun<float>» in declaration of primary template
19 | float fun<float>()
| ^~~~~~~~~~
/home/aleksey/Документы/Проекты/tests/color-c/source/app.cpp:19:11: ошибка: «float A::fun()» cannot be overloaded with «bool A::fun()»
/home/aleksey/Документы/Проекты/tests/color-c/source/app.cpp:13:10: замечание: предыдущая декларация «bool A::fun()»
13 | bool fun<bool>()
| ^~~~~~~~~
/home/aleksey/Документы/Проекты/tests/color-c/source/app.cpp:24:15: ошибка: явная специализация в не-namespace области «class A»
24 | template <>
| ^
/home/aleksey/Документы/Проекты/tests/color-c/source/app.cpp:25:12: ошибка: template-id «fun<double>» in declaration of primary template
25 | double fun<double>()
| ^~~~~~~~~~~
/home/aleksey/Документы/Проекты/tests/color-c/source/app.cpp:25:12: ошибка: «double A::fun()» cannot be overloaded with «bool A::fun()»
/home/aleksey/Документы/Проекты/tests/color-c/source/app.cpp:13:10: замечание: предыдущая декларация «bool A::fun()»
13 | bool fun<bool>()
| ^~~~~~~~~
/home/aleksey/Документы/Проекты/tests/color-c/source/app.cpp: В функции-члене «T A::fun()»:
/home/aleksey/Документы/Проекты/tests/color-c/source/app.cpp:9:19: ошибка: expected type-specifier before «Exception»
9 | throw new Exception("unsupported colormodel");
| ^~~~~~~~~
/home/aleksey/Документы/Проекты/tests/color-c/source/app.cpp: В функции «int main(int, const char**)»:
/home/aleksey/Документы/Проекты/tests/color-c/source/app.cpp:33:18: ошибка: нет декларации «fun» в этой области видимости
33 | auto test1 = fun<float>();
| ^~~
/home/aleksey/Документы/Проекты/tests/color-c/source/app.cpp:33:22: ошибка: expected primary-expression before «float»
33 | auto test1 = fun<float>();
| ^~~~~
/home/aleksey/Документы/Проекты/tests/color-c/source/app.cpp:34:22: ошибка: expected primary-expression before «double»
34 | auto test2 = fun<double>();
| ^~~~~~
/home/aleksey/Документы/Проекты/tests/color-c/source/app.cpp:35:22: ошибка: expected primary-expression before «int»
35 | auto test3 = fun<int>();
I googled some similar questions about this purpose but most of the answers suggest only solutions with templates class, not template function in non-templated class. However, I've found this question. But the date of this question is 2014. Since the date of this one c++ get many changes. Maybe is there any way to specialize a function in a class without wrapping the function to separate class?
I have the following sample code.
template<class T, class... Args>
T add(T first, Args... rest) {
return first + add(rest...);
}
int add(int a, int b) {
return a + b;
}
When I run it through clang-check -ast-dump, I get the following tree.
FunctionDecl 0x4df0b08 <tmp.cpp:2:1, line:4:1> line:2:3 add 'T (T, Args...)'
|-ParmVarDecl 0x4df0928 <col:7, col:9> col:9 referenced first 'T'
|-ParmVarDecl 0x4df09f8 <col:16, col:24> col:24 referenced rest 'Args...' pack
`-CompoundStmt 0x4df0dd0 <col:30, line:4:1>
`-ReturnStmt 0x4df0dc0 <line:3:5, col:31>
`-BinaryOperator 0x4df0da0 <col:12, col:31> '<dependent type>' '+'
|-DeclRefExpr 0x4df0cd0 <col:12> 'T' lvalue ParmVar 0x4df0928 'first' 'T'
`-CallExpr 0x4df0d78 <col:20, col:31> '<dependent type>'
|-UnresolvedLookupExpr 0x4df0cf0 <col:20> '<overloaded function type>' lvalue (ADL) = 'add' 0x4df0ba8
`-PackExpansionExpr 0x4df0d58 <col:24, col:28> '<dependent type>' lvalue
`-DeclRefExpr 0x4df0d38 <col:24> 'Args' lvalue ParmVar 0x4df09f8 'rest' 'Args...'
FunctionDecl 0x4df0f60 <tmp.cpp:6:1, line:8:1> line:6:5 add 'int (int, int)'
|-ParmVarDecl 0x4df0e00 <col:9, col:13> col:13 used a 'int'
|-ParmVarDecl 0x4df0e80 <col:16, col:20> col:20 used b 'int'
`-CompoundStmt 0x4df10b0 <col:23, line:8:1>
`-ReturnStmt 0x4df10a0 <line:7:5, col:16>
`-BinaryOperator 0x4df1080 <col:12, col:16> 'int' '+'
|-DeclRefExpr 0x4df1010 <col:12> 'int' lvalue ParmVar 0x4df0e00 'a' 'int'
`-DeclRefExpr 0x4df1030 <col:16> 'int' lvalue ParmVar 0x4df0e80 'b' 'int'
I would like to write a matcher for the first case, where one of the arguments of the function is variadic. From the AST Matcher Reference, I have found that there is a isVariadic matcher, though as the documentation says,
Example matches f, but not g or h. The function i will not match, even when
compiled in C mode.
void f(...);
void g(int);
template <typename... Ts> void h(Ts...);
void i();
Is there any way to match the variadic parameter function declaration, and further bind the variadic parameter declaration to some node? I would like to do something like functionDecl(has(parmVarDecl(hasType(packExpansionType().bind("parameter_type"))))), but it seems that this not possible since there is no packExpansionType matcher. Am I missing something here?
For future reference, I found a solution to this. It is actually possible to define custom matchers within a check.
namespace {
const AstTypeMatcher<PackExpansionType> packExpansionType;
const internal::VariadicDynCastAllOfMatcher<Stmt, PackExpansionExpr> packExpansionExpr;
}
// You can also use the macros from ASTMatchersMacros.h
...
I'm beginner with libtooling, I try to learn with easy c++ code. I try to parse/print typedef expression like below lines:
namespace DEBUG {
typedef void(*function_pointer_t)(int&);
typedef int myInt;
}
clang++ -Xclang -ast-dump -fsyntax-only output:
`-NamespaceDecl 0x3e4fe331a8 <test.h:3:1, line:7:1> line:3:11 TESTS
|-TypedefDecl 0x3e4fe333b8 <line:4:2, col:42> col:18 function_pointer_t 'double (*)(int &)'
| `-PointerType 0x3e4fe33350 'double (*)(int &)'
| `-ParenType 0x3e4fe332f0 'double (int &)' sugar
| `-FunctionProtoType 0x3e4fe332b0 'double (int &)' cdecl
| |-BuiltinType 0x3e4fe32b60 'double'
| `-LValueReferenceType 0x3e4fe33210 'int &'
| `-BuiltinType 0x3e4fe32a40 'int'
`-TypedefDecl 0x3e4fe33420 <line:5:2, col:14> col:14 myInt 'int'
`-BuiltinType 0x3e4fe32a40 'int'
To parse it I create a class that inherite from MatchFinder::MatchCallback and overload MatchFinder::MatchCallback::run:
class TypdefDeclFinder : public MatchFinder::MatchCallback {
public:
virtual void run(const MatchFinder::MatchResult& result)
{
auto Item = result.Nodes.getNodeAs<clang::TypedefDecl>("typedefDeclMatch");
if (!Item) return;
if (!IsDeclFromInputFiles(Item, result.SourceManager)) return;
if (!Item->getIdentifier()) return;
if (IsInsideTemplateContext(Item)) return;
print(Item);
}
};
But the Item pointer is equal to null. I can parse/print function, variable, class, struct template, method templates, enum ... with MacthFinder::MatchCallback, but this way doesn't run on typedef.
What's wrong with this code?