I'm trying to port some code written for MSVC over to compile on Clang. However it seems to be having a problem finding some template functions. Here is part of the definition of the struct that is giving me problems:
template< typename T > struct FixedVector
{
T * ptr;
size_t count;
typedef T value_type;
FixedVector():ptr(0),count(0) {}
~FixedVector()
{
DeleteArr(ptr); // Error message appears here
count=0;
}
// ...
}
The DeleteArr(ptr) function refers to a function defined later on, like so:
template< typename T > inline void DeleteArr( T *& ptr )
{
delete[] ptr;
ptr = NULL;
}
This is the error message I get on the line indicated:
error: call to function 'DeleteArr' that is neither visible in the template definition nor found by argument-dependent lookup
Looking at the full drop-down list for the error (in Xcode), the following message is at the bottom of the list:
'DeleteArr' should be declared prior to the call site or in an associated namespace of one of its arguments.
Clicking on this message brings me to the definition of the DeleteArr() function, as shown above.
This apparently compiled fine in MSVC, and from looking around at the differences between Clang and MSVC, this is due to a quirk in MSVC that doesn't require functions like this to be defined before they're used, as long as there is a definition somewhere. So I looked up this error message in the Clang documentation (relevant part is under the title "Unqualified lookup in templates") and it suggested adding a forward declaration before the template definition. So I added this above the definition for FixedVector:
template< typename T > inline void DeleteArr( T *& ptr );
However, this error message is still coming up, and that final bit of the error message (the 'should be declared prior to the call site' bit) still points to the actual definition of the function. Does anyone know what may be the problem? I'm all out of ideas as to how this is valid on MSVC. Also, since the error message can find the definition of the function, why is it saying it can't be found?
UPDATE: At the advice of the comments, I've added the implementation of DeleteArr() to where I declared it above the template. This seems to result in the same error! I'm really stumped now.
The declaration of DeleteArr must be available to FixedVector, i.e. the definition of the former has to come before the use by the latter. This is likely related to the failure of MSVC to correctly implement the two-phase lookup.
first define DeleteArr
template< typename T > inline void DeleteArr( T *& ptr )
{
delete[] ptr;
ptr = NULL;
}
Then define fixedvector
template< typename T > struct FixedVector
{
T * ptr;
size_t count;
typedef T value_type;
FixedVector():ptr(0),count(0) {}
~FixedVector()
{
DeleteArr(ptr); // Error message appears here
count=0;
}
// ...
}
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;
...
In a library of mine, I have the following bit of code (snipped for brevity):
namespace memory {
namespace managed {
namespace detail {
template <typename T>
inline T get_scalar_range_attribute(
region_t region,
cudaMemRangeAttribute attribute)
{ /* snip */ }
} // namespace detail
struct region_t : public memory::region_t {
// snip
bool is_read_mostly() const
{
return detail::get_scalar_range_attribute<bool>(
*this, cudaMemRangeAttributeReadMostly);
}
// snip
}
} // namespace managed
} // namespace memory
Now, with GCC and Clang on Linux, this works fine. But with MSVC 16.8.4 on Windows, a user of mine gets:
error : template instantiation resulted in unexpected function type of "__nv_bool
(cuda::memory::managed::region_t, cudaMemRangeAttribute)" (the meaning of a name
may have changed since the template declaration -- the type of the template is "T
(cuda::memory::region_t, cudaMemRangeAttribute)"
I don't understand how an instantiation can result in something unexpected, ever. I also don't see how my "name hiding" of one class name with another should have any effect on the template instantiation.
(Credit goes to #Guillaume Racicot for most of this.)
The issue here is the timing of name lookup.
Other compiles, when encountering the template declaration, region_t, seem to look for previously-defined region_t's; find memory::region_t; and be ok with that. (Correct me if I'm wrong).
MSVC, however, performs the lookup twice: Once when encountering the declaration+definition, then again upon instantiation - with different contexts both times. So, the first time, it finds memory::region_t; and the second time it finds memory::managed::region_t. This is "unexpected"...
This behavior of MSVC is apparently due to its "permissive" compilation mode (which is enabled by default). This is a bit weird, seeing how it is less permissive in this case, but that's just how it is.
I have an odd issue in MSVS 2010. I have a class with a function that is templitized and contains an parameter with a default value.
In my header file:
typedef unsinged int data32
class myClass
{
private:
...
public:
...
template <typename T>
T* myF(data32);
}
...
template<typename T>
T* myClass::myF(data32 size = 1)
{
...
}
Ok, now in my main i have something like this:
int main()
{
myClass A;
data32* myInt = A.myF<data32>(100); // no complaints from pre-compiler
data32* myInt2 = A.myF<data32>(); // pre-compiler complains "Error: no instance of the function template "myClass::myF" matches the argument list"
}
I understand why it is unhappy as i do not have a function prototype defined for 'myF()' in the class, but shouldn't it know better? I thought the point of defaults were to make the parameters optional in the call. The code DOES compile and run just fine even thought the pre-compiler is unhappy and flags this as a problem.
Any thoughts??
Thanks!
There are bugs (false alarms) in the intellisense analyzer in VS 2010. And this seems like one of them. The analyzer used for intellisense is different from the actual parser used in compiler.
I think I've run into a (possible) VC6 (I know. It's what we use.) compiler error, but am open to the fact that I've just missed something dumb. Given the following code (It's just an example!):
#include <iostream>
// Class with template member function:
class SomeClass
{
public:
SomeClass() {};
template<class T>
T getItem()
{
return T();
};
};
// Dummy just used to recreate compiler error
class OtherClass
{
public:
OtherClass() {};
};
std::ostream& operator<<( std::ostream& oStr, const OtherClass& obj )
{
return oStr << "OtherClass!";
};
// Main illustrates the error:
int main(int argc, char* argv[])
{
SomeClass a;
OtherClass inst2 = a.getItem<OtherClass>(); // Error C2275 happens here!
std::cout << inst2 << std::endl;
return 0;
}
If I try to compile this code VC6, dies on a.getItem<OtherClass>() yielding:
Error C2275: 'OtherClass' : illegal use of this type as an expression.
Have I overlooked some trivial syntax issue? Am I breaking a rule?
This code compiles just fine under gcc 4.3.4. Is it yet another compliance issue with VC6?
Thanks!
Among many other things with the word template in it, VC6 couldn't deal with function templates where the template parameters aren't also function parameters. The common workaround was to add a dummy function parameter:
template<class T>
T getItem(T* /*dummy*/ = NULL)
{
return T();
} // note: no ; after function definitions
However, in general, VC6 is pretty lame and often chokes as soon as a TU contains the template keyword. I had to beat my head against it for several years (big code base compiled with several compilers/compiler versions; VC6 giving us an endless amount of trouble) and was very glad when I got rid of it in 2003.
This is likely to be a VC6 issue. Although VC6 compiles most basic templates correctly it is known to have many issues when you start to move towards the more advanced template uses. Member templates are an area where VC6 is known to be weak on conformance.
I believe that's another bug in VC6, you should really switch to a more up-to-date compiler.
Is there any way to check if a given function is declared with C-linkage (that is, with extern "C") at compile-time?
I am developing a plugin system. Each plugin can supply factory functions to the plugin-loading code. However, this has to be done via name (and subsequent use of GetProcAddress or dlsym). This requires that the functions be declared with C-linkage so as to prevent name-mangling. It would be nice to be able to throw a compiler error if the referred-to function is declared with C++-linkage (as opposed to finding out at runtime when a function with that name does not exist).
Here's a simplified example of what I mean:
extern "C" void my_func()
{
}
void my_other_func()
{
}
// Replace this struct with one that actually works
template<typename T>
struct is_c_linkage
{
static const bool value = true;
};
template<typename T>
void assertCLinkage(T *func)
{
static_assert(is_c_linkage<T>::value, "Supplied function does not have C-linkage");
}
int main()
{
assertCLinkage(my_func); // Should compile
assertCLinkage(my_other_func); // Should NOT compile
}
Is there a possible implementation of is_c_linkage that would throw a compiler error for the second function, but not the first? I'm not sure that it's possible (though it may exist as a compiler extension, which I'd still like to know of). Thanks.
I agree with Jonathan Leffler that this probably is not possible in a standard way. Maybe it would be possible somewhat, depending on the compiler and even version of the compiler, but you would have to experiment to determine possible approaches and accept the fact that the compiler's behavior was likely unintentional and might be "fixed" in later versions.
With g++ version 4.4.4 on Debian Squeeze, for example, you might be able to raise a compiler error for functions that are not stdcall with this approach:
void my_func() __attribute__((stdcall));
void my_func() { }
void my_other_func() { }
template <typename ret_, typename... args_>
struct stdcall_fun_t
{
typedef ret_ (*type)(args_...) __attribute__((stdcall));
};
int main()
{
stdcall_fun_t<void>::type pFn(&my_func),
pFn2(&my_other_func);
}
g++ -std=c++0x fails to compile this code because:
SO2936360.cpp:17: error: invalid conversion from ‘void ()()’ to ‘void ()()’
Line 17 is the declaration of pFn2. If I get rid of this declaration, then compilation succeeds.
Unfortunately, this technique does not work with cdecl.
For Unix/Linux, how about analyzing the resulting binary with 'nm' and looking for symbol names? I suppose it's not what you meant, but still it's sort of compile time.