Note: I know this question was asked in different ways, but I couldn't solve it based on my restrictions:
I am using google test version 1.7
Compiling in Visual studio 2010, with platform toolset V100
I am writing google test for a library I have created.
In my library, I have 3 structs, as follows:
struct utc_clock{ .... }
struct system_clock {....}
struct cpu_clock {....}
moreover, I have another class that uses them as template parameters.
In my test case, I do as follows:
TEST(MyTest, testImportantThings)
{
time_point<utc_clock> tp = utc_clock::now();
ASSERT_EQ(..things with tp... );
... more ASSERTION
}
What I am trying to do, is to run
TEST(MyTest, testImportantThings)
multiple times for each of the utc_clock, system_clock, cpu_clock
I have looked into How to get gtest TYPED_TEST parameter type,
after that, I got the following:
template<typename T>
struct MyTest: public testing::Test{
using MyParamType = T;
};
using MyTypes = testing::TYpes<utc_clock, system_clock, cpu_clock>;
TYPED_TEST_CASE(MyTest, MyTypes);
TYPED_TEST(MyTest, testImportantStuff)
{
using clock = typename TestFixture::MyParamType;
timepoint<clock> tp = clock::now();
ASSERT_EQ(..things with tp... );
... more ASSERTION
}
But I get the following errors:
unexpected token(s) preceding ';' on: using MyParamType = T;
testing::internal::TYpeList use of class template requires template
arguement list online on: using MyTypes = testing::TYpes<utc_clock, system_clock, cpu_clock>;
and more...
It is possible that your compiler is too old to support defining type aliases with using. What if you replace those with old-style typedef statements?
For example, you could replace
using MyParamType = T;
With the equivalent:
typedef T MyParamType;
Related
I have a project with quite a lot of function templates that I wrote back in Visual Studio 2017, and it always worked fine. Now I have to build it in VS2019, because I need to include the lib in another project that is written in VS2019, and the thing won't build.
There is one function template it seems to take issue with, although it doesn't actually complain about the function itself. The compiler just says "identifier not found" when I invoke it in the code. The thing is there in the namespace, however, even InteliSense sees it and links to it without complaining. Just the compiler won't.
Here's the code in question:
// declaration
namespace Oparse
{
// lots of other functions, many of them templates
template <typename T> OpModel<T> *_ModelPtr(T *receiver) { return new OpModel<T>(receiver); };
}
// Invocation
namespace Oparse
{
template <class T, class U>
class OpModelFactory
: public OpNestable
{
public:
OpModelFactory<T, U>(vector<U*> &receiver) : OpNestable(OP_MODELFACTORY), receiver(receiver) {};
// other stuff
void Serialize(string key, stringstream &stream, unsigned int indents)
{
for (unsigned int i = 0; i < receiver.size(); ++i)
{
// check if the instances are really of the type of this OpModel, otherwise there may be duplicates between polymorphic factories populating the same receiver.
T *currentModel = dynamic_cast<T*>(receiver[i]);
if (currentModel != NULL)
{
OpModel<T> *parser = _ModelPtr<T>(currentModel); // <-- identifier not found
parser->Serialize(key, stream, indents);
delete parser;
}
}
};
private:
vector<U*> &receiver;
}
}
If I comment that invocation, the project builds, despite there being a whole lot more function templates declared right where this one is. I have no clue what to do to make the linker find it. Are there any Visual Studio wizzards who could give me a hint? I must honestly confess that I haven't used the IDE in years, and it's my first time in Visual Studio 2019...
Here's the complete output of the error. There's a second message to it, but I found it perfectly unhelpful:
1>D:\Orbiter_installs\Orbiter2016\Orbitersdk\Oparse\include\OpModel.h(138,27): error C3861: '_ModelPtr': identifier not found
1>D:\Orbiter_installs\Orbiter2016\Orbitersdk\Oparse\include\OpModel.h(152): message : see reference to class template instantiation 'Oparse::OpModelFactory<T,U>' being compiled
And no, there's not further message attached. I have seen similar messages that usually go on with "with ... $further information", but this is all I get.
There is a circular dependency problem.
In Oparse.h, you first include OpModel.h that requires_ModelPtr in implementation of Serialize , but_ModelPtr is only defined later in the header.
You need to forward declare the template method.
In OpModel.h, write this instead:
namespace Oparse
{
template<typename T> class OpModel;
template <typename T> OpModel<T>* _ModelPtr(T* receiver);
// Remaining of OpModel.h...
typedef map<string, pair<Oparse::OpValue*, vector<Oparse::OpValidator*>>> OpModelDef;
typedef vector<pair<Oparse::OpValue*, vector<Oparse::OpValidator*>>> OpValues;
...
When using the C++ LLVM-vs2014 configuration in Visual Studio 2015, this static assert fails. The assert does not fail in clang++, gcc, or even Visual C++. The thiscall attribute is stuck on the function type, even though it's no longer applicable. I've filed a bug report, but I'd like to know if there's a way to forcefully remove the attribute in the meantime. Can thiscall be removed?
#include <type_traits>
template<typename T>
struct remove_member_pointer;
template<typename T, typename U>
struct remove_member_pointer<T U::*> {
using type = T;
};
struct foo;
using input = void(foo::*)();
using expect = void();
using result = typename remove_member_pointer<input>::type;
//This static_assert fails because there is a
//compiler-generated attribute left behind, making
//the type of result actually `void () __attribute__((thiscall))`
static_assert(std::is_same<result, expect>{}, "");
int main() { return{}; }
Microsoft Visual Studio Community 2015
Version 14.0.24720.00 Update 1
I did not find a workaround for VS 2015 Update 1, but this issue does appear to be fixed in VS 2015 Update 2.
Using VS2013, I can create a typedef to a function type like so:
typedef void ResponseCallback(std::string const&);
Is it possible to use type aliasing (I have access to C++11 features) to do the same? I've been trying to migrate away from using typedef as using seems to be more consistent going forward. I've tried something like below but it does not work:
using ResponseCallback = void (std::string const&);
I get a vaguely unhelpful error message from Visual Studio 2013 as follows:
error C2061: syntax error : identifier 'string'
You can however wrap it.
template < typename P1 >
using ResponseCallback =
typename std::remove_pointer < void (*)( P1 const & ) >::type;
I tested it on VS2013 and heres the coliru
Or a simple bogus wrapper like this will satisfy VS2013 too:
template < typename functype >
struct functype_wrapper
{
typedef functype type;
};
//using ResponseCallback = void ( std::string const & ); // nope
using ResponseCallback = functype_wrapper < void ( std::string const & ) >::type; // oke
Since you have -std=c++11 available, you may want to use the newer convention for this type of functionality.
#include <functional>
typedef std::function<void(std::string const &)> ResponseCallback;
This would allow you to do what you're trying to do, as well as utilize lambdas, functors, or function pointers.
Various comments to my question verified I am using the alias correctly, which lead me to believe this might be a tooling problem. I tested the same alias on Clang and GCC and it worked just fine. So this must just be another unsupported/poorly implemented C++11 feature in Visual Studio 2013.
I do however recommend #Slyps excellent answer for applicable workarounds.
I'm currently trying to write an Artemis like game component/entity system in C++. I was planning on getting this system to work with a cross platform tool for writing applications on Android and iOS called MoSync.
Unfortunately MoSync currently uses an old version of GCC and when porting the library that I had been testing in Visual Studio, I got a whole bunch of errors. Most of these I could solve, but there is one bug with templates that I can't get my head around.
I wrote a small example
template <typename T>
struct Base
{
static int type;
};
struct Derived : public Base<Derived>
{
};
template <typename T>
int Base<T>::type(-1);
extern "C" int MAMain()
{
Derived d;
d.type = 0;
}
My library uses the Curiously Recursive Template Pattern for defining Components. This example compiles fine in GCC 4.4 and Visual Studio 2010. However when I try to compile this in MoSync (which uses GCC 3.4.6) I get this linker error
C:\MoSync\workspace\pede\main.cpp: Error: Unresolved symbol '__ZN4BaseI7DerivedE4typeE',
Is there a workaround to get this to work in this compiler, or will I have to find another way to define my Components?
Edit*
In fact I can make this error occur with an even simpler example:
template <typename T>
struct Component {
static int t;
};
template <typename T>
int Component<T>::t(-1);
extern "C" int MAMain()
{
Component<int>::t = 0;
}
Gives this error
C:\MoSync\workspace\Components\main.cpp:9: Error: Unresolved symbol '__ZN9ComponentIiE1tE',
I guess this might not have anything to do with the Curiously Recursive Template Pattern at all. What can I do to get this to compile under GCC 3.4.6?
According to this bug report on the gcc bugtracker, the problem is caused by specifying a default value in the static variable definition. The code should link if you remove the initialisation as so:
int Base<T>::type;
The bug report seems to have been resolved as not a bug. Despite this, your samples compile fine in GCC 4.4.
To work around this, you can use a class type with a constructor that will automatically initialise itself.
Does adding
int Base<Derived>::type(-1);
helps ?
gcc 3.4 is really starting to be old and don't coep well with template sorcery.
I'm using Visual Studio 2008 with the Boost v1.42.0 library. If I use an enum as the template argument, I get a compile error when adding a value using push_back(). The compiler error is: 'T': is not a legal base class and the location of the error is move.hpp line 79.
#include <boost/interprocess/containers/vector.hpp>
class Test {
public:
enum Types {
Unknown = 0,
First = 1,
Second = 2,
Third = 3
};
typedef boost::container::vector<Types> TypesVector;
};
int main() {
Test::TypesVector o;
o.push_back(Test::First);
return 0;
}
If I use a std::vector instead it works. And if I resize the Boost version first and then set the values using the [] operator it also works.
Is there some way to make this work using push_back()?
Template backtrace of the error:
error C2516: 'T' : is not a legal base class
1> main.cpp(21) : see declaration of 'T'
1> main.cpp(21) : see reference to class template instantiation 'boost::interprocess::rv' being compiled
1> with
1> [
1> T=Test::Types
1> ]
I think you have find really a bug. I have posted to the Boost ML to track the issue and try to have more info.
For the moment the single workaround I see is to specialize the rv class as follows, but I'm not sure this will work on all the cases.
namespace boost {
namespace interprocess {
template <>
class rv<Test::Types>
{
Test::Types v;
rv();
~rv();
rv(rv const&);
void operator=(rv const&);
operator Test::Types() const {return v;}
};
}}
If this do not works you can try using int instead of enum.
enum {
Unknown = 0,
First = 1,
Second = 2,
Third = 3
};
typedef int Types;
Of course this has the drawback to loss the enum safety.
It sounds like Boost has some erroneous logic to determine whether to derive from T or not.
Naively, one might assume that any type besides a native type or pointer may be used as a base. However enums are neither bases nor primitive. Perhaps they failed to account for that.
It looks like Boost is incorrectly determining that enums are compatible with its rvalue-reference emulation.
The best way to solve this is to avoid use of enums in Boost Interprocess structures.
A hack like
namespace boost {
namespace interprocess { // get inside boost
template<>
class is_movable<Test::Types> // add custom specialization of is_movable
: public ::boost::mpl::bool_<false>
{};
}}
might patch things up. Untested.
Add this right after your #includes so it appears before the first use.