4

I want to mark as deprecated some method of my interface. For backward compatibility I need to support old method for some time.

// my own interface for other
interface I {
    [[deprecated( "use 'bar' instead" )]]
    virtual void foo() = 0;
};

But Visual Studio 2015 don't allow me to implement this interface:

// my own implementation
class IImpl : public I {
public:
    virtual void foo() override; // here goes warning C4996:
                                 // 'I::foo': was declared deprecated
};

I use option Treat Wanings as Errors (/WX), so this code can't be compiled.

I try to ignore the warning locally:

class IImpl : public I {
public:
#pragma warning(push)
#pragma warning(disable: 4996)
    virtual void foo() override;
#pragma warning(pop)
    // ... other methods are outside
};

But it has no effect. The only solution, that allows to compile the code is ignoring the warning for entire class declaration:

#pragma warning(push)
#pragma warning(disable: 4996)
class IImpl : public I {
public:
    virtual void foo() override;
    // ... other methods are also affected
};
#pragma warning(pop)

GCC seems to make things right:

#pragma GCC diagnostic error "-Wdeprecated-declarations"

interface I {
    [[deprecated]]
    virtual void foo() = 0;
};

class IImpl : public I {
public:
    virtual void foo() override; // <<----- No problem here
};

int main()
{
    std::shared_ptr<I> i( std::make_shared<IImpl>() );
    i->foo(); // <<---ERROR: 'virtual void I::foo()' is deprecated [-Werror=deprecated-declarations]
    return 0;
}

Is it the bug of MSVC++? Is there any way to use deprecated declaration correctly in Visual Studio?

ildjarn
  • 62,044
  • 9
  • 127
  • 211
  • What is the point of declaring a function `[[deprecated]]` and then disable the warning? – nwp Aug 18 '16 at 16:17
  • http://stackoverflow.com/a/295229/612920 – Mansuro Aug 18 '16 at 16:17
  • @nwp, the declaration is for users of my interface. I'm provider of interface. – Andrianov Andrey Aug 18 '16 at 16:18
  • @Mansuro I've also tried __declspec(deprecated). It gives absolutely the same behaviour – Andrianov Andrey Aug 18 '16 at 16:20
  • So you want the library to detect if you or someone else is sitting in front of the keyboard? That is gonna be hard to implement. Just don't use the deprecated interface. Either it should not be implemented or it should not be deprecated, one of them has to go to have any sanity. – nwp Aug 18 '16 at 16:22
  • @nwp of course i provide header file with interface class. What is the use of deprecated and not implemented method? Warning? Ignore warning -> Dynamic linking error. – Andrianov Andrey Aug 18 '16 at 16:27
  • 2
    The proper way is to disable the warning for entire class definition. Since the warning is not actually hit on the line of your prototype... – Kupto Aug 18 '16 at 16:28
  • @Kupto: But then he also won't be warned if his class makes use of deprecated interfaces of other libraries. – celtschk Aug 18 '16 at 18:30
  • @celtschk: Not really, he is an interface provider, what other interfaces does the class specification need to support? Note that this way of avoiding warnings will not affect definitions file... – Kupto Aug 18 '16 at 22:37
  • 1
    @Kupto: A private variable may be of a deprecated type from another library. That's not part of the public interface, but still needs to be written in the class definition. And I'd say it's worthwhile to be warned about that deprecation. – celtschk Aug 18 '16 at 22:49
  • @celtschk: please, make sure to read what I have just wrote! – Kupto Aug 18 '16 at 23:01
  • 1
    @Kupto: Please make sure that you **understand** what I just wrote! In particular: *Where* do you declare private member variables? – celtschk Aug 19 '16 at 06:43
  • @celtschk where do you initialize and use them? – Kupto Aug 23 '16 at 06:29
  • @Kupto: Doesn't matter: He didn't get the error on use of the deprecated function, but on a declaration referring to it. And further, in my scenario, it's not the *private variable* that is deprecated, it is the variable's *type*. And that is used at the point of declaring the private member variable (note that the type must be complete at that point, which clearly indicates use). And of course you don't initialize a type, ever. – celtschk Aug 23 '16 at 07:26

1 Answers1

2

The standard says:

Implementations may use the deprecated attribute to produce a diagnostic message in case the program refers to a name or entity other than to declare it

but the declaration of IImpl::foo does not refer to I::foo.

This passage is informative, and need not be followed to the letter. Indeed, an implementation may warn you about whatever it wants. Still I would still consider it a bug.

It can be worked around like this:

// IInternal.h
struct I {
   virtual void foo() = 0; // no deprecation
};

// I.h
#include <IInternal.h>
[[deprecated( "use 'bar' instead" )]]
inline void I::foo() { 
    std::cerr << "pure virtual function I::foo() called\n"; 
    abort(); 
} 

//IImpl.h
#include <IInternal.h>
class IImpl : public I { ... // whatever
n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243