Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 949611
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 15, 20262026-05-15T23:25:46+00:00 2026-05-15T23:25:46+00:00

Can we increase the re-usability for this key-oriented access-protection pattern : class SomeKey {

  • 0

Can we increase the re-usability for this key-oriented access-protection pattern:

class SomeKey { 
    friend class Foo;
    // more friends... ?
    SomeKey() {} 
    // possibly non-copyable too
};

class Bar {
public:
    void protectedMethod(SomeKey); // only friends of SomeKey have access
};

To avoid continued misunderstandings, this pattern is different from the Attorney-Client idiom:

  • It can be more concise than Attorney-Client (as it doesn’t involve proxying through a third class)
  • It can allow delegation of access rights
  • … but its also more intrusive on the original class (one dummy parameter per method)

(A side-discussion developed in this question, thus i’m opening this question.)

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-15T23:25:46+00:00Added an answer on May 15, 2026 at 11:25 pm

    I like this idiom, and it has the potential to become much cleaner and more expressive.

    In standard C++03, I think the following way is the easiest to use and most generic. (Not too much of an improvement, though. Mostly saves on repeating yourself.) Because template parameters cannot be friends, we have to use a macro to define passkey’s:

    // define passkey groups
    #define EXPAND(pX) pX
    
    #define PASSKEY_1(pKeyname, pFriend1)                             \
            class EXPAND(pKeyname)                                    \
            {                                                         \
            private:                                                  \
                friend EXPAND(pFriend1);                              \
                EXPAND(pKeyname)() {}                                 \
                                                                      \
                EXPAND(pKeyname)(const EXPAND(pKeyname)&);            \
                EXPAND(pKeyname)& operator=(const EXPAND(pKeyname)&); \
            }
    
    #define PASSKEY_2(pKeyname, pFriend1, pFriend2)                   \
            class EXPAND(pKeyname)                                    \
            {                                                         \
            private:                                                  \
                friend EXPAND(pFriend1);                              \
                friend EXPAND(pFriend2);                              \
                EXPAND(pKeyname)() {}                                 \
                                                                      \
                EXPAND(pKeyname)(const EXPAND(pKeyname)&);            \
                EXPAND(pKeyname)& operator=(const EXPAND(pKeyname)&); \
            }
    // and so on to some N
    
    //////////////////////////////////////////////////////////
    // test!
    //////////////////////////////////////////////////////////
    struct bar;
    struct baz;
    struct qux;
    void quux(int, double);
    
    struct foo
    {
        PASSKEY_1(restricted1_key, struct bar);
        PASSKEY_2(restricted2_key, struct bar, struct baz);
        PASSKEY_1(restricted3_key, void quux(int, double));
    
        void restricted1(restricted1_key) {}
        void restricted2(restricted2_key) {}
        void restricted3(restricted3_key) {}
    } f;
    
    struct bar
    {
        void run(void)
        {
            // passkey works
            f.restricted1(foo::restricted1_key());
            f.restricted2(foo::restricted2_key());
        }
    };
    
    struct baz
    {
        void run(void)
        {
            // cannot create passkey
            /* f.restricted1(foo::restricted1_key()); */
    
            // passkey works
            f.restricted2(foo::restricted2_key());
        }
    };
    
    struct qux
    {
        void run(void)
        {
            // cannot create any required passkeys
            /* f.restricted1(foo::restricted1_key()); */
            /* f.restricted2(foo::restricted2_key()); */
        }
    };
    
    void quux(int, double)
    {
        // passkey words
        f.restricted3(foo::restricted3_key());
    }
    
    void corge(void)
    {
        // cannot use quux's passkey
        /* f.restricted3(foo::restricted3_key()); */
    }
    
    int main(){}
    

    This method has two drawbacks: 1) the caller has to know the specific passkey it needs to create. While a simple naming scheme (function_key) basically eliminates it, it could still be one abstraction cleaner (and easier). 2) While it’s not very difficult to use the macro can be seen as a bit ugly, requiring a block of passkey-definitions. However, improvements to these drawbacks cannot be made in C++03.


    In C++0x, the idiom can reach its simplest and most expressive form. This is due to both variadic templates and allowing template parameters to be friends. (Note that MSVC pre-2010 allows template friend specifiers as an extension; therefore one can simulate this solution):

    // each class has its own unique key only it can create
    // (it will try to get friendship by "showing" its passkey)
    template <typename T>
    class passkey
    {
    private:
        friend T; // C++0x, MSVC allows as extension
        passkey() {}
    
        // noncopyable
        passkey(const passkey&) = delete;
        passkey& operator=(const passkey&) = delete;
    };
    
    // functions still require a macro. this
    // is because a friend function requires
    // the entire declaration, which is not
    // just a type, but a name as well. we do 
    // this by creating a tag and specializing 
    // the passkey for it, friending the function
    #define EXPAND(pX) pX
    
    // we use variadic macro parameters to allow
    // functions with commas, it all gets pasted
    // back together again when we friend it
    #define PASSKEY_FUNCTION(pTag, pFunc, ...)               \
            struct EXPAND(pTag);                             \
                                                             \
            template <>                                      \
            class passkey<EXPAND(pTag)>                      \
            {                                                \
            private:                                         \
                friend pFunc __VA_ARGS__;                    \
                passkey() {}                                 \
                                                             \
                passkey(const passkey&) = delete;            \
                passkey& operator=(const passkey&) = delete; \
            }
    
    // meta function determines if a type 
    // is contained in a parameter pack
    template<typename T, typename... List>
    struct is_contained : std::false_type {};
    
    template<typename T, typename... List>
    struct is_contained<T, T, List...> : std::true_type {};
    
    template<typename T, typename Head, typename... List>
    struct is_contained<T, Head, List...> : is_contained<T, List...> {};
    
    // this class can only be created with allowed passkeys
    template <typename... Keys>
    class allow
    {
    public:
        // check if passkey is allowed
        template <typename Key>
        allow(const passkey<Key>&)
        {
            static_assert(is_contained<Key, Keys>::value, 
                            "Passkey is not allowed.");
        }
    
    private:
        // noncopyable
        allow(const allow&) = delete;
        allow& operator=(const allow&) = delete;
    };
    
    //////////////////////////////////////////////////////////
    // test!
    //////////////////////////////////////////////////////////
    struct bar;
    struct baz;
    struct qux;
    void quux(int, double);
    
    // make a passkey for quux function
    PASSKEY_FUNCTION(quux_tag, void quux(int, double));
    
    struct foo
    {    
        void restricted1(allow<bar>) {}
        void restricted2(allow<bar, baz>) {}
        void restricted3(allow<quux_tag>) {}
    } f;
    
    struct bar
    {
        void run(void)
        {
            // passkey works
            f.restricted1(passkey<bar>());
            f.restricted2(passkey<bar>());
        }
    };
    
    struct baz
    {
        void run(void)
        {
            // passkey does not work
            /* f.restricted1(passkey<baz>()); */
    
            // passkey works
            f.restricted2(passkey<baz>());
        }
    };
    
    struct qux
    {
        void run(void)
        {
            // own passkey does not work,
            // cannot create any required passkeys
            /* f.restricted1(passkey<qux>()); */
            /* f.restricted2(passkey<qux>()); */
            /* f.restricted1(passkey<bar>()); */
            /* f.restricted2(passkey<baz>()); */
        }
    };
    
    void quux(int, double)
    {
        // passkey words
        f.restricted3(passkey<quux_tag>());
    }
    
    void corge(void)
    {
        // cannot use quux's passkey
        /* f.restricted3(passkey<quux_tag>()); */
    }
    
    int main(){}
    

    Note with just the boilerplate code, in most cases (all non-function cases!) nothing more ever needs to be specially defined. This code generically and simply implements the idiom for any combination of classes and functions.

    The caller doesn’t need to try to create or remember a passkey specific to the function. Rather, each class now has its own unique passkey and the function simply chooses which passkey’s it will allow in the template parameters of the passkey parameter (no extra definitions required); this eliminates both drawbacks. The caller just creates its own passkey and calls with that, and doesn’t need to worry about anything else.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I need a priority queue where I can increase or decrease the priority key.
This isn't a question for a real-life project; I'm only curious. We can increase
I have two tables in my Database.This can increase later on.I want to add
Is there any way by which I can increase the default width of the
Following a question posted here about how I can increase the speed on one
When you surf with your browser, you can increase or decrease the font dimension
How can I increase django execution time of a view. Some views of my
how can we increase or decrese the size of div on btn click in
I am developing an eCommerce website which contains around 2000-3000 products(no.can be increase in
Can we have alternate Row color to GtkMenu items? and how to increase menu

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.