3 回答

TA貢獻(xiàn)1797條經(jīng)驗(yàn) 獲得超6個(gè)贊
我喜歡這個(gè)成語(yǔ),它有可能變得更干凈,更具表現(xiàn)力。
在標(biāo)準(zhǔn)C ++ 03中,我認(rèn)為以下方式最容易使用且最通用。(但是沒(méi)有太大的改進(jìn)。大多數(shù)情況下可以節(jié)省自己重復(fù)。)因?yàn)槟0鍏?shù)不能成為朋友,所以我們必須使用宏來(lái)定義passkey:
// 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(){}
此方法有兩個(gè)缺點(diǎn):1)調(diào)用者必須知道它需要?jiǎng)?chuàng)建的特定密鑰。雖然簡(jiǎn)單的命名方案(function_key)基本上消除了它,但它仍然可以是一個(gè)抽象清潔器(并且更容易)。2)雖然使用宏并不是很困難,但可能會(huì)看起來(lái)有點(diǎn)難看,需要一組passkey-definitions。但是,在C ++ 03中無(wú)法對(duì)這些缺點(diǎn)進(jìn)行改進(jìn)。
在C ++ 0x中,成語(yǔ)可以達(dá)到其最簡(jiǎn)單,最具表現(xiàn)力的形式。這是由于可變參數(shù)模板和允許模板參數(shù)成為朋友。(請(qǐng)注意,2010年之前的MSVC允許模板專(zhuān)家說(shuō)明符作為擴(kuò)展;因此可以模擬此解決方案):
// 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(){}
僅注意樣板代碼,在大多數(shù)情況下(所有非功能情況?。┒疾恍枰貏e定義。該代碼通常簡(jiǎn)單地為類(lèi)和函數(shù)的任何組合實(shí)現(xiàn)慣用語(yǔ)。
調(diào)用者不需要嘗試創(chuàng)建或記住特定于該函數(shù)的密鑰。相反,每個(gè)類(lèi)現(xiàn)在都有自己唯一的密碼,函數(shù)只需在passkey參數(shù)的模板參數(shù)中選擇允許的密鑰(不需要額外的定義); 這消除了這兩個(gè)缺點(diǎn)。調(diào)用者只是創(chuàng)建自己的密鑰并使用它調(diào)用,而不需要擔(dān)心其他任何事情。
- 3 回答
- 0 關(guān)注
- 601 瀏覽
添加回答
舉報(bào)