2

I am getting a compilation error so clearly I am doing something wrong but I am not sure how to fix it nor if it is possible to have explicit instantiation and SFINAE. The reproducible example is minimal so it might not make complete sense but essentially there is a vector alike class that can be instantiated for unique_ptr or observer_ptr. The SFINAE part is to only allow for the add function to be available only for the unique_ptr.

I got a define there CompilationFail. It seems that if Bar has a FooPtrVectorView then I get an compilation error. If I dont define it then all is good. If I just use FooPtrVectorView say in a function (and not part of Bar) there are no issues.

The compiler error for msvc is error C3190: 'Foo *FooSmartPtrVector::add(void)' with the provided template arguments is not the explicit instantiation of any member function of 'FooSmartPtrVector'

For msvc users I have a zip file with the whole solution which might make it easier https://app.box.com/s/nzbgvxo58u4jmiw50o1hlh28yfyxo1d1

observer_ptr.h

template<typename T>
class observer_ptr
{
};

Foo.h and rest of implementation in .cpp

struct Foo{};

FooSmartPtrVector.h

#define CompilationFail 1

class Bar;
// this has to be forward declared in my case
struct Foo; 

template<template<class...> class SmartPtr>
class FooSmartPtrVector 
{
public:
    #if CompilationFail
    const Foo* fooBar(const Bar* const bar) const;
    #endif

    template<template<class...> class Q = SmartPtr,
             typename std::enable_if_t<std::is_same<Q<Foo>, std::unique_ptr<Foo>>::value>* = nullptr>
    Foo* add();

private:
    std::vector<SmartPtr<Foo>> vec;
};

using FooPtrVectorView = FooSmartPtrVector<nonstd::observer_ptr>;
using FooPtrVector = FooSmartPtrVector<std::unique_ptr>;

FooSmartPtrVector.cpp

#include "FooSmartPtrVector.h"

#if CompilationFail
    #include "Bar.h"
#endif 

#if CompilationFail
template<template<class...> class SmartPtr>
const Foo* FooSmartPtrVector<SmartPtr>::fooBar(const Bar* const bar) const
{
    return bar->getFromFooPtrView();
}
#endif 

template<template<class...> class SmartPtr>
template<template<class...> class Q,
         typename std::enable_if_t<std::is_same<Q<Foo>, std::unique_ptr<Foo>>::value>*>
Foo* FooSmartPtrVector<SmartPtr>::add()
{
    auto uptr_foo = std::make_unique<Foo>();
    auto foo = uptr_foo.get();
    vec.emplace_back(std::move(uptr_foo));
    return foo;
}


// explicit instantiations of our templates
template class FooSmartPtrVector<observer_ptr>;
template class FooSmartPtrVector<std::unique_ptr>;
template Foo* FooSmartPtrVector<std::unique_ptr>::add();

Bar.h

#include "FooSmartPtrVector.h"

struct Foo;

class Bar
{
public:
    Foo* getFromFooPtrView() const { return nullptr; }

private:
    bool isValid_;
    FooPtrVectorView observations_vector_;
};

Any help is appreciated.

xerion
  • 303
  • 2
  • 11
  • Could you upload the zip somewhere else? [Box is having DNS problems.](http://www.eweek.com/security/ddos-attack-snarls-friday-morning-internet-traffic.html) – kirbyfan64sos Oct 21 '16 at 18:51
  • Compiles fine [here](http://coliru.stacked-crooked.com/a/2203e619d40a063c) for gcc/clang – Jarod42 Oct 21 '16 at 18:53
  • Have you try `template Foo* FooSmartPtrVector::add();` ? – Jarod42 Oct 21 '16 at 18:58
  • @kirbyfan64sos https://www.dropbox.com/s/u9ts4fsude3vjqp/ConsoleApplication4.zip?dl=0 – xerion Oct 21 '16 at 19:02
  • @Jarod42 will give it a try soon and report back – xerion Oct 21 '16 at 19:04
  • @Jarod42 just `<>` should be fine with the default arguments – krzaq Oct 21 '16 at 19:21
  • @Jarod42 what you proposed works fine, but what is the explanation behind it. Why is that it is needed in this case? If the CompilationFail is 0 then all is good so I am trying to understand why? – xerion Oct 21 '16 at 19:30
  • @krzaq the default arguments do not work – xerion Oct 21 '16 at 19:31
  • @xerion I think I'd file that under msvc quirk. – krzaq Oct 21 '16 at 19:31
  • @xerion: As that compiles with gcc/clang, I would say it is a msvc bug (Parsing c++ is not a trivial task though). So help compiler to remove *tricky* part. – Jarod42 Oct 21 '16 at 19:52
  • While this works fine in the reproduction case in my code I get this error `error C2672: 'FooSmartPtrVector::add': no matching overloaded function found` `error C2783: 'Foo *FooSmartPtrVectorSmartPtrVector::add(void)': could not deduce template argument for '__formal'` Not sure how to decifer that – xerion Oct 22 '16 at 07:39
  • Seems that for every time I call add I will instead have to call it as `f.add()` which is a bit annoying but OK. Though I still dont get how in a small reproduction case it is all good and I only need to specify it say in the explicit function instantiation, while in my code I have to do it also when I call it... I get that it might be a bit more complex but the compiler would still parse both as the same I would think. – xerion Oct 22 '16 at 07:48

0 Answers0